防sql注入之参数绑定 SQL Injection Attacks and Defense 预处理语句与存储过程
http://php.net/manual/zh/pdo.prepared-statements.php
预处理语句与存储过程
很多更成熟的数据库都支持预处理语句的概念。什么是预处理语句?可以把它看作是想要运行的 SQL 的一种编译过的模板,它可以使用变量参数进行定制。预处理语句可以带来两大好处:
- 查询仅需解析(或预处理)一次,但可以用相同或不同的参数执行多次。当查询准备好后,数据库将分析、编译和优化执行该查询的计划。对于复杂的查询,此过程要花费较长的时间,如果需要以不同参数多次重复相同的查询,那么该过程将大大降低应用程序的速度。通过使用预处理语句,可以避免重复分析/编译/优化周期。简言之,预处理语句占用更少的资源,因而运行得更快。
 - 提供给预处理语句的参数不需要用引号括起来,驱动程序会自动处理。如果应用程序只使用预处理语句,可以确保不会发生SQL 注入。(然而,如果查询的其他部分是由未转义的输入来构建的,则仍存在 SQL 注入的风险)。
 
预处理语句如此有用,以至于它们唯一的特性是在驱动程序不支持的时PDO 将模拟处理。这样可以确保不管数据库是否具有这样的功能,都可以确保应用程序可以用相同的数据访问模式。
http://php.net/manual/en/pdo.prepared-statements.php
Prepared statements and stored procedures
Many of the more mature databases support the concept of prepared statements. What are they? They can be thought of as a kind of compiled template for the SQL that an application wants to run, that can be customized using variable parameters. Prepared statements offer two major benefits:
- The query only needs to be parsed (or prepared) once, but can be executed multiple times with the same or different parameters. When the query is prepared, the database will analyze, compile and optimize its plan for executing the query. For complex queries this process can take up enough time that it will noticeably slow down an application if there is a need to repeat the same query many times with different parameters. By using a prepared statement the application avoids repeating the analyze/compile/optimize cycle. This means that prepared statements use fewer resources and thus run faster.
 - The parameters to prepared statements don't need to be quoted; the driver automatically handles this. 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).
 
Prepared statements are so useful that they are the only feature that PDO will emulate for drivers that don't support them. This ensures that an application will be able to use the same data access paradigm regardless of the capabilities of the database.
w pdo
业务驱动技术
<?php
$ReadParametersList = array('w_start_unix', 'w_count', 'CreatedAfter', 'CreatedBefore','NextToken');
foreach ($ReadParametersList as $w) {
$wfile = 'D:\cmd\\' . $w . '.w';
$handle = fopen($wfile, 'r');
$wb = fread($handle, filesize($wfile));
echo $wb . "\r\n";
} try {
$dbh = new PDO('mysql:host=localhost;dbname=apiamz',"root", "root");
$sql = 'SELECT COUNT(*) FROM listorders';
foreach($dbh->query($sql) as $row) {
print_r($row);
}
$dbh = null;
} catch (PDOException $e) {
print "Error!: " . $e->getMessage() . "<br/>";
die();
} die();
Example #1 用预处理语句进行重复插入
下面例子通过用 name 和 value 替代相应的命名占位符来执行一个插入查询
<?php
$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)");
$stmt->bindParam(':name', $name);
$stmt->bindParam(':value', $value);
// 插入一行
$name = 'one';
$value = 1;
$stmt->execute();
//  用不同的值插入另一行
$name = 'two';
$value = 2;
$stmt->execute();
?>Example #2 用预处理语句进行重复插入
下面例子通过用 name 和 value 取代 ? 占位符的位置来执行一条插入查询。
<?php
$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (?, ?)");
$stmt->bindParam(1, $name);
$stmt->bindParam(2, $value);
// 插入一行
$name = 'one';
$value = 1;
$stmt->execute();
// 用不同的值插入另一行
$name = 'two';
$value = 2;
$stmt->execute();
?>Example #3 使用预处理语句获取数据
下面例子获取数据基于键值已提供的形式。用户的输入被自动用引号括起来,因此不会有 SQL 注入攻击的危险。
<?php
$stmt = $dbh->prepare("SELECT * FROM REGISTRY where name = ?");
if ($stmt->execute(array($_GET['name']))) {
  while ($row = $stmt->fetch()) {
    print_r($row);
  }
}
?>如果数据库驱动支持,应用程序还可以绑定输出和输入参数.输出参数通常用于从存储过程获取值。输出参数使用起来比输入参数要稍微复杂一些,因为当绑定一个输出参数时,必须知道给定参数的长度。如果为参数绑定的值大于建议的长度,就会产生一个错误。
Example #4 带输出参数调用存储过程
<?php
$stmt = $dbh->prepare("CALL sp_returns_string(?)");
$stmt->bindParam(1, $return_value, PDO::PARAM_STR, 4000); 
// 调用存储过程
$stmt->execute();
print "procedure returned $return_value\n";
?>还可以指定同时具有输入和输出值的参数,其语法类似于输出参数。在下一个例子中,字符串“hello”被传递给存储过程,当存储过程返回时,hello 被替换为该存储过程返回的值。
Example #5 带输入/输出参数调用存储过程
<?php
$stmt = $dbh->prepare("CALL sp_takes_string_returns_string(?)");
$value = 'hello';
$stmt->bindParam(1, $value, PDO::PARAM_STR|PDO::PARAM_INPUT_OUTPUT, 4000); 
// 调用存储过程
$stmt->execute();
print "procedure returned $value\n";
?>Example #6 占位符的无效使用
<?php
$stmt = $dbh->prepare("SELECT * FROM REGISTRY where name LIKE '%?%'");
$stmt->execute(array($_GET['name']));
// 占位符必须被用在整个值的位置
$stmt = $dbh->prepare("SELECT * FROM REGISTRY where name LIKE ?");
$stmt->execute(array("%$_GET[name]%"));
?>SQL Injection Attacks and Defense 
Second Edition
Using parameterized statements 
As we discussed in previous chapters, one of the root causes of SQL injection is the creation of 
SQL  queries  as  strings  that  are  then  sent  to  the  database  for  execution.  This  behavior, 
commonly known as dynamic string building or dynamic SQL, is one of the primary causes of 
an application being vulnerable to SQL injection. 
As  a  more  secure  alternative  to  dynamic  string  building,  most  modern  programming 
languages  and  database  access  application  program  interfaces  (APIs)  allow  you  to  provide 
parameters  to  a  SQL  query  through  the  use  of  placeholders,  or  bind  variables,  instead  of 
working directly with the user input. Commonly known as parameterized statements, these are 
a safer alternative that can avoid or solve many of the common SQL injection issues you will 
see  within  an  application,  and  you  can  use  them  in  most  common  situations  to  replace  an 
existing  dynamic  query.  They  also  have  the  advantage  of  being  very  efficient  on  modern 
databases,  as  the  database  can  optimize  the  query  based  on  the  supplied  prepared  statement, 
increasing the performance of subsequent queries. 
I should note, however, that parameterized statements are a method of supplying potentially 
insecure parameters to the database, usually  as a query  or stored procedure  call. They  do not 
alter  the  content  of  the  values  that  are  passed  to  the  database,  though,  so  if  the  database 
functionality  being  called  uses  dynamic  SQL  within  the  stored  procedure  or  function 
implementation  it  is  still  possible  for  SQL  injection  to  occur.  This  has  historically  been  a 
problem with Microsoft SQL Server and Oracle, both of which have shipped with a number of 
built-in stored procedures that were vulnerable to SQL injection in the past, and it is a danger 
that you should be aware of with any database stored procedures or functions that use dynamic 
SQL  in  their  implementation.  An  additional  issue  to  consider  is  that  malicious  content  could 
have  been  stored  in  the  database  at  this  point  that  may  then  be  used  elsewhere  in  the 
application,  causing  SQL  injection  at  another  point  in  the  application.  We  discussed  this  in 
Chapter 7, in “Exploiting second-order SQL injection.” 
Here is an example of a vulnerable piece of login page pseudocode using dynamic SQL. We 
will discuss how to parameterize this code in Java, C#, and PHP in the following sections: Username = request(“username”) 
Password = request(“password”) 
Sql = “SELECT 
∗
 FROM users WHERE username=’” + Username + “‘ AND password=’”+ Password + “’” 
Result = Db.Execute(Sql) 
If (Result) /
∗
 successful login 
∗
/ 
Tools & traps… 
What Can be Parameterized, and What Can’t? 
Not all dynamic SQL statements can be parameterized. In particular, you can parameterize only data values, and 
not SQL identifiers or keywords. Therefore, you can’t have parameterized statements such as the following: 
SELECT 
∗
 FROM ? WHERE username = ‘john’ 
SELECT ? FROM users WHERE username = ‘john’ 
SELECT 
∗
 FROM users WHERE username LIKE ‘j%’ ORDER BY ? 
Unfortunately, a common solution presented in online forums to solve this problem is to use dynamic SQL in 
the string that is then used to parameterize the query, as in the following example: 
String sql = “SELECT 
∗
 FROM ” + tbl Name + “ WHERE user =?”; 
In this case, you can end up introducing an SQL injection issue where there previously wasn’t one by trying to 
parameterize a statement. 
In general, if you’re trying to supply an SQL identifier as a parameter, you should look at your SQL and how 
you’re  accessing  your  database  first,  and  then  look  at  whether  it  is  possible  to  rewrite  the  query  using  a  fixed 
identifier.  Although  it  may  be  possible  to  solve  this  through  the  use  of  dynamic  SQL,  this  is  also  likely  to 
adversely affect the performance of the query, as the database will not be able to optimize the query. If dynamic 
SQL  is  required,  ensure  that  known  value  validation  (discussed  later  in  this  chapter)  is  performed  to  validate 
identifiers in the database metadata where possible.







https://golang.google.cn/pkg/database/sql/
type Stmt func (s *Stmt) Close() error func (s *Stmt) Exec(args ...interface{}) (Result, error) func (s *Stmt) ExecContext(ctx context.Context, args ...interface{}) (Result, error) func (s *Stmt) Query(args ...interface{}) (*Rows, error) func (s *Stmt) QueryContext(ctx context.Context, args ...interface{}) (*Rows, error) func (s *Stmt) QueryRow(args ...interface{}) *Row func (s *Stmt) QueryRowContext(ctx context.Context, args ...interface{}) *Row
https://github.com/go-sql-driver/mysql/search?q=Stmt
SQL 注入漏洞
应用安全开发指南 - 支付宝开放平台 https://opendocs.alipay.com/open/200/security
SQL 注入漏洞
漏洞描述
SQL 注入攻击(SQL Injection),被广泛用于非法获取网站控制权,是发生在应用程序的数据库层上的安全漏洞。 在设计不良的程序当中,忽略了对输入字符串中夹带的 SQL 指令的检查,那么这些夹带进去的指令就会被数据库误认为是正常的 SQL 指令而运行,从而使数据库受到攻击,可能导致数据被窃取、更改、删除,以及进一步导致网站被嵌入恶意代码、被植入后门程序等危害。
漏洞危害
机密数据被窃取。
核心业务数据被篡改。
网页被篡改。
数据库所在服务器被攻击变为傀儡主机,甚至企业网被入侵。
解决方案
所有的查询语句都使用数据库提供的参数化查询接口,参数化的语句使用参数而不是将用户输入变量嵌入到 SQL 语句中。
对进入数据库的特殊字符 '"\<>&*; 等进行转义处理,或编码转换。
确认每种数据的类型,比如数字型的数据就必须是数字,数据库中的存储字段必须对应为 int 型。
数据长度应该严格规定,能在一定程度上防止比较长的 SQL 注入语句无法正确执行。
网站每个数据层的编码统一,建议全部使用 UTF-8 编码,上下层编码不一致有可能导致一些过滤模型被绕过。
严格限制网站所用数据库账号的权限,给此用户仅提供能够满足其工作的权限,从而最大限度的减少注入攻击对数据库的危害。
避免网站显示 SQL 错误信息,比如类型错误、字段不匹配等,防止攻击者利用这些错误信息进行一些判断。
示例代码
ASP 漏洞代码示例
<%
 Dim oComm, oRs
 Set id = Request.QueryString("d")
 Set oConn = Server.CreateObject("ADODB.Connection")
 oConn.Open "Provider=MSDAORA;Password=sth;Persist Security Info=True;User ID=whats;Data Source=mescp"
 Set oComm = CreateObject("ADODB.Command")
 oComm.ActiveConnection = oConn
 oComm.CommandType = 1
 oComm.CommandText = "select * from all_objects where rownum ="& id
 Set oRs = oComm.Execute
 %>
ASP 修复示例
<%
 Dim oComm, oRs
 Set oConn = Server.CreateObject("ADODB.Connection")
 oConn.Open "Provider=MSDAORA;Password=sth;Persist Security Info=True;User ID=whats;Data Source=mescp"
 Set oComm = CreateObject("ADODB.Command")
 oComm.ActiveConnection = oConn
 oComm.CommandType = 1
 oComm.CommandText = "select * from all_objects where rownum = ? "
 oComm.Parameters.Append
 oComm.CreateParameter("v1",3,1,4,100)
 Set oRs = oComm.Execute
 %>
PHP 漏洞代码示例
<?php
 $id = $_GET [ 'id' ];
 $conn   =   mysql_connect ( " localhost" , " root" , " " )  or   die  ( " wrong!" );
 $sel = mysql_select_db ( " mydb" , $conn );
 $sql = " select * from user where id = " . id
 $que = mysql_query ( $sql , $conn );
 ?>
PHP 修复示例
<?php
 $id = $_GET [ 'id' ];
 $conn   =   mysql_connect ( " localhost" , " root" , " " )  or   die  ( " wrong!" );
 $sel = mysql_select_db ( " mydb" , $conn );
 $sql = " select * from user where id = :id"
 $stmt   =   $conn -> prepare ( $sql );
 $stmt -> execute ( array ( ':id' => $id ));
 ?>
JAVA 漏洞代码示例
JdbcConnection   conn   =   new   JdbcConnection ();
 final   String   sql   =   "select * from product where pname like '%"
          +   request . getParameter ( "pname" )  +   "%'" ;
 conn . execqueryResultSet ( sql );
JAVA 修复示例
JdbcConnection   conn   =   new   JdbcConnection ();
 PreparedStatement   pstmt   =   conn . prepareStatement ( "select * from product where pname like ?" ;
 pstmt . setString ( 1 ,  “ % ” +   request . getParameter ( "pname" ) + ” % ” );
 pstmt . execute ();
SQL 注入漏洞
漏洞描述
SQL 注入攻击(SQL Injection),被广泛用于非法获取网站控制权,是发生在应用程序的数据库层上的安全漏洞。 在设计不良的程序当中,忽略了对输入字符串中夹带的 SQL 指令的检查,那么这些夹带进去的指令就会被数据库误认为是正常的 SQL 指令而运行,从而使数据库受到攻击,可能导致数据被窃取、更改、删除,以及进一步导致网站被嵌入恶意代码、被植入后门程序等危害。
漏洞危害
机密数据被窃取。
核心业务数据被篡改。
网页被篡改。
数据库所在服务器被攻击变为傀儡主机,甚至企业网被入侵。
解决方案
所有的查询语句都使用数据库提供的参数化查询接口,参数化的语句使用参数而不是将用户输入变量嵌入到 SQL 语句中。
对进入数据库的特殊字符 '"\<>&*; 等进行转义处理,或编码转换。
确认每种数据的类型,比如数字型的数据就必须是数字,数据库中的存储字段必须对应为 int 型。
数据长度应该严格规定,能在一定程度上防止比较长的 SQL 注入语句无法正确执行。
网站每个数据层的编码统一,建议全部使用 UTF-8 编码,上下层编码不一致有可能导致一些过滤模型被绕过。
严格限制网站所用数据库账号的权限,给此用户仅提供能够满足其工作的权限,从而最大限度的减少注入攻击对数据库的危害。
避免网站显示 SQL 错误信息,比如类型错误、字段不匹配等,防止攻击者利用这些错误信息进行一些判断。
示例代码
ASP 漏洞代码示例
<%
 Dim oComm, oRs
 Set id = Request.QueryString("d")
 Set oConn = Server.CreateObject("ADODB.Connection")
 oConn.Open "Provider=MSDAORA;Password=sth;Persist Security Info=True;User ID=whats;Data Source=mescp"
 Set oComm = CreateObject("ADODB.Command")
 oComm.ActiveConnection = oConn
 oComm.CommandType = 1
 oComm.CommandText = "select * from all_objects where rownum ="& id
 Set oRs = oComm.Execute
 %>
ASP 修复示例
<%
 Dim oComm, oRs
 Set oConn = Server.CreateObject("ADODB.Connection")
 oConn.Open "Provider=MSDAORA;Password=sth;Persist Security Info=True;User ID=whats;Data Source=mescp"
 Set oComm = CreateObject("ADODB.Command")
 oComm.ActiveConnection = oConn
 oComm.CommandType = 1
 oComm.CommandText = "select * from all_objects where rownum = ? "
 oComm.Parameters.Append
 oComm.CreateParameter("v1",3,1,4,100)
 Set oRs = oComm.Execute
 %>
PHP 漏洞代码示例
<?php
 $id = $_GET [ 'id' ];
 $conn   =   mysql_connect ( " localhost" , " root" , " " )  or   die  ( " wrong!" );
 $sel = mysql_select_db ( " mydb" , $conn );
 $sql = " select * from user where id = " . id
 $que = mysql_query ( $sql , $conn );
 ?>
PHP 修复示例
<?php
 $id = $_GET [ 'id' ];
 $conn   =   mysql_connect ( " localhost" , " root" , " " )  or   die  ( " wrong!" );
 $sel = mysql_select_db ( " mydb" , $conn );
 $sql = " select * from user where id = :id"
 $stmt   =   $conn -> prepare ( $sql );
 $stmt -> execute ( array ( ':id' => $id ));
 ?>
JAVA 漏洞代码示例
JdbcConnection   conn   =   new   JdbcConnection ();
 final   String   sql   =   "select * from product where pname like '%"
          +   request . getParameter ( "pname" )  +   "%'" ;
 conn . execqueryResultSet ( sql );
JAVA 修复示例
JdbcConnection   conn   =   new   JdbcConnection ();
 PreparedStatement   pstmt   =   conn . prepareStatement ( "select * from product where pname like ?" ;
 pstmt . setString ( 1 ,  “ % ” +   request . getParameter ( "pname" ) + ” % ” );
 pstmt . execute ();												
											防sql注入之参数绑定 SQL Injection Attacks and Defense 预处理语句与存储过程的更多相关文章
- 防sql注入之参数绑定  SQL Injection Attacks and Defense
		
http://php.net/manual/zh/pdo.prepared-statements.php 预处理语句与存储过程 很多更成熟的数据库都支持预处理语句的概念.什么是预处理语句?可以把它看作 ...
 - 黑马程序员_ADO.Net(ExecuteReader,Sql注入与参数添加,DataSet,总结DataSet与SqlDataReader )
		
转自https://blog.csdn.net/u010796875/article/details/17386131 一.执行有多行结果集的用ExecuteReader SqlDateReader ...
 - js防止sql注入的参数过滤
		
js防止sql注入的参数过滤 <script language="javascript"> <!-- var url = location.search; var ...
 - Exploiting second-order SQL injection  利用二阶注入获取数据库版本信息  SQL Injection Attacks and Defense  Second Edition
		
w SQL Injection Attacks and Defense Second Edition Exploiting second-order SQL injection Virtually ...
 - sql注入学习笔记,什么是sql注入,如何预防sql注入,如何寻找sql注入漏洞,如何注入sql攻击 (原)
		
(整篇文章废话很多,但其实是为了新手能更好的了解这个sql注入是什么,需要学习的是文章最后关于如何预防sql注入) (整篇文章废话很多,但其实是为了新手能更好的了解这个sql注入是什么,需要学习的是文 ...
 - Statement和PreparedStatement的区别; 什么是SQL注入,怎么防止SQL注入?
		
问题一:Statement和PreparedStatement的区别 先来说说,什么是java中的Statement:Statement是java执行数据库操作的一个重要方法,用于在已经建立数据库连接 ...
 - Statement和PreparedStatement的区别; 什么是SQL注入,怎么防止SQL注入? (转)
		
问题一:Statement和PreparedStatement的区别 先来说说,什么是java中的Statement:Statement是java执行数据库操作的一个重要方法,用于在已经建立数据库连接 ...
 - 【sql注入】浅谈sql注入中的Post注入
		
[sql注入]浅谈sql注入中的Post注入 本文来源:i春秋学院 00x01在许多交流群中,我看见很多朋友对于post注入很是迷茫,曾几何,我也是这样,因为我们都被复杂化了,想的太辅助了所以导致现在 ...
 - [转]SQL注入漏洞及绑定变量浅谈
		
1.一个问题引发的思考 大家在群里讨论了一个问题,奉文帅之命写篇作文,且看: String user_web = "user_web" String sql = "upd ...
 
随机推荐
- (六)、mkdir--创建目录make directory
			
一.命令详解与命令格式 在文件系统中创建新的目录, 格式:mkdir [-选项] 目录名 目录名既可以是相对路径名,也可是相对路径名 选项: -p或者--parent,创建指定路径中所有不存在 ...
 - Linux腾讯云下安装mysql
			
百度云盘下载地址https://pan.baidu.com/s/1MqUEdeqZuQbq-veLuVItQQ 将下载好的mysql-5.7.14-linux-glibc2.5-x86_64.tar. ...
 - [leetcode]120.Triangle三角矩阵从顶到底的最小路径和
			
Given a triangle, find the minimum path sum from top to bottom.Each step you may move to adjacent nu ...
 - java上下分页窗口流动布局
			
上下分页要用到 JSplitPane jSplitPane =new JSplitPane();//设定为拆分布局 效果图: show me code: import java.awt.event.C ...
 - 运行命令区分webpack环境,以及axios数据请求的封装
			
在开发环境和线上环境时,由于环境的不同,有时候需要修改一定的代码,可以通过配置webpack环境来减少对代码的修改:另外,有时候去看别人的代码,你可能都找不到他的数据请求在什么位置,最近在做一个vue ...
 - (class: org/apache/jasper/runtime/PageContextImpl, method: getELResolver signature: ()Ljavax/el/ELResolver;) Incompatible argument to
			
网上大多都说是jsp版本原因: 引用: .............................................. ................................. ...
 - 第十八章节 BJROBOT 安卓手机 APP 建地图【ROS全开源阿克曼转向智能网联无人驾驶车】
			
1.把小车平放在地板上,用资料里的虚拟机,打开一个终端 ssh 过去主控端启动roslaunch znjrobotbringup.launch 2.在虚拟机端再打开一个终端,ssh 过去主控端启动ro ...
 - mysql词法分析和语法分析
			
如果没有命中查询缓存,就要开始真正执行语句了.首先,MySQL 需要知道你要做什么,因此需要对 SQL 语句做解析.分析器先会做"词法分析".你输入的是由多个字符串和空格组成的一条 ...
 - Vue3.0聊天室|vue3+vant3仿微信聊天实例|vue3.x仿微信app界面
			
一.项目简介 基于Vue3.0+Vant3.x+Vuex4.x+Vue-router4+V3Popup等技术开发实现的仿微信手机App聊天实例项目Vue3-Chatroom.实现了发送图文表情消息/g ...
 - PHP 导出到Excel表格中
			
/** * 导出excel * @throws \PHPExcel_Exception * @throws \PHPExcel_Reader_Exception * @throws \PHPExcel ...