- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我刚刚开始我的第一个项目(为了好玩)。我正在学习 PHP 和 MySQL,并且已经完成了我的第一个工作应用程序。它有效,但我现在正在学习如何保护我的应用程序,从而防止 SQL 注入(inject)。我有大约 50 多个 PHP 文件来管理与我的 MySQL 数据库的交互。它们看起来都像这样:
<?php
$inputvalues = $_POST;
$errors = false;
$result = false;
session_start();
$uid = $_SESSION['usr_id'];
$mysqli = new mysqli('localhost', "root", "", "testdb");
if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}
foreach ($inputvalues as $key => $value) {
if(isset($value) && !empty($value)) {
$inputvalues[$key] = $mysqli->real_escape_string( $value );
} else {
$errors[$key] = 'The field '.$key.' is empty';
}
}
if( !$errors ) {
$addresult = "
SELECT a.firstnames, a.surname, a.schoolrole, a.datejoined FROM teachers a LEFT JOIN schools b ON a.schoolid = b.id WHERE b.id = '".$inputvalues['schoolid']."'
";
if( $result = $mysqli->query($addresult) ) {
while($row = $result->fetch_all())
{
$returnResult = $row;
}
}
}
mysqli_close($mysqli);
echo json_encode(['result' => $returnResult, 'errors' => $errors]);
exit;
?>
这是我在整个应用程序中用于从数据库读取和写入数据的格式。如果我需要将它们更改为准备好的语句,我不插入任何信息而只是检索它们,我将如何处理?
此外,如果我没有向数据库输入任何数据,它是否仍然容易受到注入(inject)攻击?
能否请您提供一个示例,说明如何使我当前的代码适应准备好的语句,我将不胜感激。
最佳答案
我也遇到过这种情况。我也在使用连接语句,然后我将我的应用程序切换为准备好的语句。
坏消息是您将更改通过将客户端数据连接到 SQL 语句而构建的每个 SQL 语句,这几乎是您 50 个源文件中的每个 SQL 语句。
好消息是切换到预处理语句的好处是无价的,例如:
1-你永远不会担心所谓的“SQL 注入(inject)攻击”
PHP manual说
If an application exclusively uses prepared statements, the developer can be sure that no SQL injection will occur (however, if other portions of the query are being built up with unescaped input, SQL injection is still possible).
对我来说,这个理由——内心的平静——足以支付更改我的源代码的成本。 , 现在您的客户可以在表单名称字段中键入 robert; DROP 表学生; -- ;)
并且您感到安全,不会发生任何事情
2- 您不再需要转义客户端参数。您可以直接在 SQL 语句中使用它们,例如:
$query = "SELECT FROM user WHERE id = ?";
$vars[] = $_POST['id'];
代替
$id = $mysqli->real_escape_string($_POST['id']);
$query = "SELECT FROM user WHERE id = $id";
这是你在使用准备好的语句之前必须做的事情,这让你有忘记像普通人一样转义一个参数的危险。攻击者破坏您的系统所需要做的只是 1 个未转义的参数。
通常更改源文件总是有风险并且会带来痛苦,尤其是当您的软件设计很糟糕并且您没有明显的测试计划时。但我会告诉你我做了什么让它尽可能简单。
我做了一个每个数据库交互代码都会用到的函数,所以你以后可以在一个地方改变你想要的东西——那个函数——你可以做这样的东西
class SystemModel
{
/**
* @param string $query
* @param string $types
* @param array $vars
* @param \mysqli $conn
* @return boolean|$stmt
*/
public function preparedQuery($query,$types, array $vars, $conn)
{
if (count($vars) > 0) {
$hasVars = true;
}
array_unshift($vars, $types);
$stmt = $conn->prepare($query);
if (! $stmt) {
return false;
}
if (isset($hasVars)) {
if (! call_user_func_array(array( $stmt, 'bind_param'), $this->refValues($vars))) {
return false;
}
}
$stmt->execute();
return $stmt;
}
/* used only inside preparedQuery */
/* code taken from: https://stackoverflow.com/a/13572647/5407848 */
protected function refValues($arr)
{
if (strnatcmp(phpversion(), '5.3') >= 0) {
$refs = array();
foreach ($arr as $key => $value)
$refs[$key] = &$arr[$key];
return $refs;
}
return $arr;
}
}
现在,您可以在源文件中的任何地方使用此接口(interface),例如,让我们更改您在问题中提供的当前 SQL 语句。让我们改变这个
$mysqli = new mysqli('localhost', "root", "", "testdb");
$addresult = "
SELECT a.firstnames, a.surname, a.schoolrole, a.datejoined
FROM teachers a LEFT JOIN schools b ON a.schoolid = b.id
WHERE b.id = '".$inputvalues['schoolid']."'";
if( $result = $mysqli->query($addresult) ) {
while($row = $result->fetch_all())
{
$returnResult = $row;
}
}
进入这个
$mysqli = new mysqli('localhost', "root", "", "testdb");
$sysModel = new SystemModel();
$addresult = "
SELECT a.firstnames, a.surname, a.schoolrole, a.datejoined
FROM teachers a LEFT JOIN schools b ON a.schoolid = b.id
WHERE b.id = ?";
$types = "i"; // for more information on paramters types, please check :
//https://php.net/manual/en/mysqli-stmt.bind-param.php
$vars = [];
$vars[] = $inputvalues['schoolid'];
$stmt = $sysModel->preparedQuery($addresult, $types, $vars, $mysqli);
if (!$stmt || $stmt->errno) {
die('error'); // TODO: change later for a better illustrative output
}
$result = $stmt->get_result();
$returnResult = [];
while ($row = $result->fetch_array(MYSQLI_ASSOC)) {
$returnResult[] = $row;
}
Also, If I am not entering any data to the DB, is it still vulnerable to injection?
是的,Sql 注入(inject)攻击是通过将错误的字符串连接到您的 SQL 语句来应用的。它是 INSERT
、SELECT
、DELETE
、UPDATE
。例如
$query = "SELECT * FROM user WHERE name = '{$_GET['name']}' AND password = '{$_GET['pass']}'"
类似的东西可以被利用
// exmaple.com?name=me&pass=1' OR 1=1; --
这将产生一个 SQL 语句
$query = "SELECT * FROM user WHERE name = 'me' AND password = '1' OR 1=1; -- '"
//executing the SQL statement and getting the result
if($result->num_rows){
//user is authentic
}else{
//wrong password
}
// that SQL will always get results from the table which will be considered a correct password
祝你好运,将你的软件切换到准备好的语句,并记住,无论发生什么,你都不会受到 SQL 注入(inject)攻击,这让你高枕无忧,这值得改变源文件的成本
关于php - 切换到准备好的语句,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45031956/
我想获取当前位置并将相机移动到当前位置,然后将当前位置 (LatLng) 保存到我的数据库 我获得了 ACCESS_FINE 权限并使用以下代码,但应用程序已停止工作 double lat = map
我想稍微优化一下这部分代码,以使用 $_SESSION['user']= $arr; 这样的数组。 // Store user db info in session for use $stmt = $
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我不确定 DaemonSet 中是否存在就绪条件。我的意思是,该 DaemonSet 拥有的所有 pod 都已准备就绪。 我知道 kubectl wait ,不过好像不能检查 DaemonSet 的准
我正在编写一个 JS 模块模式来测试代码并帮助我使用 JS Fiddle 理解该模式。我不明白的是,为什么第 25 行和第 26 行的“私有(private)方法”在通过 DOM 就绪引用时,其值为未
标题中有一个非常微妙的动画。当第一次加载页面,或者使用 cmd+shift+r (mac) 刷新以清除缓存时,jQuery 似乎并没有等待 DOM 准备好。它在所有正常的 html/css 弹出之前启
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
我有两个问题: 我如何知道框架的内容已准备就绪/已加载(如 $(document.ready()))? 我如何知道弹出窗口 (window.open()) 内容已准备就绪/已加载(如 $(docume
只是想知道 document.ready 调用的数量是否会影响页面加载速度。Gulp/Grunt 有没有办法通过删除单独的文档就绪函数来丑化/缩小 JS? 最佳答案 检查一下! 我没有发现 Chrom
我有一个 的列表如下所示,它使用 Meteor.startup 填充了 find()。然后我得到这些 的所有数据属性使用 data() 并将其放入一个对象中并尝试返回/console.log 它以
我正在使用 trego 主题。作为主题选项,您可以设置和更改将出现在站点中的文本(例如“版权文本”和“ Logo url”的文本)。我如何使用 WPML 制作多语言版本?我想通过 wpml-confi
Zend_Service_Twitter 组件仍然适用于将于 2013 年 3 月 5 日弃用的 Twitters API v1.0。所以我想准备好我的新网站与 Twitter API 交互 v1.1
有没有一种优雅的方法来做到这一点?目前我只是使用自定义步骤 “并等待 10 秒”以绝对确定,有足够的时间让 iframe 做好准备。我不希望这个功能因为一个小的网络问题或 CPU 峰值而在我动力不足的
当我尝试在我的 VPS 上安装 Windows 时,我无法访问 Glish---图形网站控制台(但浏览器控制台可以工作)。 当我打开 Glish 控制台时,提示: novnc ready: nativ
生成新的全屏窗口时,相对于: sdl2.SDL_Init(sdl2.SDL_INIT_VIDEO) window = sdl2.ext.Window('win_name', (x_size, y_si
我刚刚为我的最新项目投入了 Umbraco ASP.NET CMS,我不确定这是否是全面的,但对于我的设置,Knockout.js 正在做所有的模板。 我不太热衷于 knockout.js,但到目前为
我是 jQuery 的新手,最近几天一直在尝试学习它。在我的办公室里,几乎没有经验丰富的 JavaScript 开发人员,他们主要使用 jQuery 来满足他们的所有需求,每当我找到他们并与他们交谈以
我目前正在编写一个脚本,我正在使用 while($IE.busy) {Start-Sleep 1} 等待页面准备就绪。 页面准备好后,我的脚本会填写并提交表单。我一直遇到问题,因为(我认为)IE 报告
这个问题已经有答案了: window.onload vs $(document).ready() (17 个回答) 已关闭 3 年前。 以下示例代码的执行顺序是什么?会$(window).on('lo
我是一名优秀的程序员,十分优秀!