??xml version="1.0" encoding="utf-8" standalone="yes"?> http://www.symantec.com/connect/articles/detection-sql-injection-and-cross-site-scripting-attacks 在这两年中,安全专家应该对网l应用层的攻?yn)L加重视。因为无Z有多强壮的防
火墙规则讄或者非常勤于补漏的修补机制Q如果你的网l应用程序开发者没有遵循安全代码进行开发,d者将通过80端口q入你的pȝ。广泛被使用的两个主
要攻?yn)L术是SQL注入[ref1]和CSS[ref2]d。SQL注入是指Q通过互联|的输入区域Q插入SQL
meta-charactersQ特D字W?
代表一些数据)(j)和指令,操纵执行后端的SQL查询的技术。这些攻M要针对其他组l的WEB服务器。CSSd通过在URL里插入script标签Q然?
诱导信Q它们的用L(fng)d们,保恶意Javascript代码在受害h的机器上q行。这些攻d用了(jin)用户和服务器之间的信dp,事实上服务器没有对输
入、输?gu)行检,从而未拒绝javascript代码?/p>
q篇文章讨论SQL注入和CSSd漏洞的检技术。网上已l有很多关于q两U基于WEBd的讨论,比如如何实施dQ他们的影响Q怎样更好的编
制和设计E序防止q些d?然? 对如何检这些攻dƈ没有_的讨论。我们采用流行的开源的IDS Snort[ref
3],l徏Ҏ(gu)?hu)(g)这些攻ȝ规则的正则表辑ּ。附带,Snort默认规则讑֮包含(g)CSS的方法,但是q些Ҏ(gu)被避开(g)。比如大多通过hexq制~?
??3C%73%63%72%69%70% 74%3E代替<script>避开(g)?/p>
依赖level of
paranoial织的能力,我们已经~写?jin)多U检相同攻ȝ规则。如果你希望(g)各U可能的SQL注入dQ那么你需要简单的留意M现行的SQL
meta-charactersQ如单引P分号和双重破折号。同L(fng)一个极端检CSSd的方法,只要单地提防HTML标记的角括号。但q样?x)检?
出很多错误。ؓ(f)?jin)避免这些,q些规则需要修改它检更_? 当仍然不能避免错误?/p>
在Snort规则中用pcre(Perl Compatible Regular
Expressions)[ref4]关键字,每个规则可以带或不带其他规则动作。这些规则也可以被公用Y件如grep(文档搜烦(ch)工具)使用Q来审阅|络
服务器日志?但是,需要警惕的是,用户的输入只有当以GET提交hӞW(xu)EB服务器才?x)记录日?如果是以POST提交的请求在日记中是不会(x)记录的?/p>
2. SQL注入的正则表C式 ?
你ؓ(f)SQL注入d选择正则表示式的时候,重点要记住攻击者可以通过提交表单q行SQL注入Q也可以通过Cookie区域。你的输入检逻辑应该考虑用户
l织的各cd输入(比如表单或Cookie信息)。ƈ且如果你发现许多警告来自一个规则,L(fng)意单引号或者是分号Q也怺字符是你的Web应用E序创造的
合法的在CookieS中的输入。因? (zhn)需要根据你的特D的WEB应用E序评估每个规则?/p>
依照前面提到Q一个琐l的(g)SQL入d的正则表辑ּ要留意SQLҎ(gu)的meta-characters
譬如单引?’)双重扩则?--),Z(jin)查出q些字符和他们hex{值数, 以下正则表达式适用: 2.1 (g)SQL meta-characters的正则表辑ּ /(\%27)|(’)|(--)|(\%23)|(#)/ix 解释: ?们首先检查单引号{值的hexQ单引号本n或者双重扩折号。这些是MS SQL Server或Oracle的字W? 表示后边的ؓ(f)评论,
随后的都被忽略?另外Q如果你使用MySQL,你需要留?’#’和它{值的hex的出现。注意我们不需要检查双重破折号{值的hex,
因ؓ(f)q不是HTML meta-character, 览器不?x)进行编码?q且,
如果d者设法手工修改双重破折号为它的hex?2D(使用代理像Achilles[ref 5]), SQL注入失败? alert tcp $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS (msg:"SQL
Injection - Paranoid";
flow:to_server,established;uricontent:".pl";pcre:"/(\%27)|(’)|(--)|(%23)|(#)/i";
classtype:Web-application-attack; sid:9099; rev:5;) 在本讨Z, uricontent关键字的gؓ(f)".pl ", 因ؓ(f)在我们的试环境? CGI
E序是用Perl写的。uricontent关键字的值取决于(zhn)的Ҏ(gu)应用, q个g许是".php ", ? .asp ", ? .jsp
", {?从这点考虑, 我们不显C对应的Snort 规则, 但是我们?x)给出创造这些规则的正则表达式?
通过q些正则表达式你可以很简单的创造很多的Snort规则.在前面的正则表达式里,
我们(g)双重破折号是因为:(x)即便没有单引L(fng)存在那里也可能是SQL入点[ref 6]?例如, SQL查询条目只包含数|如下: select value1, value2, num_value3 from database q种情况Q攻击者可以执行额外的SQL查询, C提交如下输入: 3; insert values into some_other_table 最? pcre的修饰符’ i’ ?#8217; x ’ 是用于分别匹配大写和忽略空白处的?
上面的规则也可以另外扩展来检查分L(fng)存在。然而,分号很可以是正常HTTP应答的一部分。ؓ(f)?jin)减这U错误,也是Z(jin)M正常的单引号和双重扩折号的出
玎ͼ上面的规则应该被修改成先(g)=L(fng)存。用戯入会(x)响应一个GET或POSThQ一般输入提交如下:(x) username=some_user_supplied_value&password=some_user_supplied_value 因此, SQL 注入试导致用L(fng)输入出现在a = h它等效的hexg后?/p>
2.2 修正(g)SQL meta-characters的正则表辑ּ /((\%3D)|(=))[^ ]*((\%27)|(’)|(--)|(\%3B)|(:))/i 解释: q个规则首先留意 = h它的hex?%3D)Q然后考虑零个或多个除换行W以外的L字符Q最后检单引号Q双重破折号或分受?/p>
典型的SQL注入?x)尝试围l单引号的用途操作原来的查询Q以便得到有用的价倹{讨个攻M般?’or’1’=’1字符? 但是,
q个串的侦查很容易被逃避Q譬如用1’or2>1 --.
然而唯一恒定的部分是最初的字符的|跟随一单引P再加’or’。随后的布尔逻辑可能在一定范围上变化Q可以是普通样式也可能是非常复杂的。这些攻d
以相当精被侦测Q通过以下的正则表辑ּ?.3章节讲解?/p>
2.3 典型?SQL 注入d的正则表辑ּ /w*((\%27)|(’))((\%6F)|o|(\%4F))((\%72)|r|(\%52))/ix 解释: union’SQL 查询在SQL注入各种数据库中d中同h很常见的。如果前面的正则表达式仅仅检单引号或则其他的SQL meta
characters
Q会(x)造成很多的错误存在。你应该q一步修Ҏ(gu)询,(g)单引号和关键字‘union’。这同样可以q一步扩展其他的SQL关键字,?#8217;select’,
’insert’, ’update’, ’delete’, {等?/p>
2.4 (g)SQL注入QUNION查询关键字的正则表达?/strong> /((\%27)|(’))union/ix (\%27)|(’) - 单引号和它的hex{? 可以同样为其他SQL查询定制表达式,?>select, insert, update, delete, drop, {等. 如果Q到q个阶段Q攻击者已l发现web应用E序存在SQL注入漏洞Q他尝试利用它。如果他认识到后端服务器式MS SQL
serverQ他一般会(x)试q行一些危险的储存和扩展储存过E。这些过E一般以‘sp’?#8216;xp’字母开头。典型的Q他可能试q行
‘xp_cmdshell’扩展储存q程Q通过SQL Server执行W(xu)indows
命o(h)Q。SQL服务器的SA权限有执行这些命令的权限。同样他们可以通过xp_regread, xp_regwrite{储存过E修Ҏ(gu)册表?/p>
2.5 (g)MS SQL Server SQL注入d的正则表辑ּ /exec(s|+)+(s|x)pw+/ix 解释: 3. 跨站脚本(CSS)的正则表辑ּ 当发动CSSd或检一个网站漏z的时?
d者可能首先ɽ单的HTML标签?lt;b>(_体),<i>(斜体)?lt;u>(下划U?Q或者他可能试单的
script标签?lt;script>alert("OK")</script>.
因ؓ(f)大多数出版物和网l传播的(g)网站是否有css漏洞都拿q个作ؓ(f)例子。这些尝试都可以很简单的被检出来?
然而,高明点的d者可能用它的hex值替换整个字W串。这?lt;script>标签?x)?3C%73%63%72%69%70%74%3E?
现?
另一斚wQ攻击者可能用web代理服务器像Achilles?x)自动{换一些特D字W如<换成%3C?gt;换成%3E.q样d发生ӞURL
中通常以hex{g替角括号?/p>
下列正则表达式将(g)Q何文本中包含的html?lt;?gt;。它?yu)捉住试图?lt;
b>?lt;u>、或<script>。这正则表达式应该忽略大写。我们需要同时检角括号和它的hex{?%
3C|<)。检hexq制转化的整个字W串Q我们必L用戯入的数字?P即用[a-z0-9%]
。这可能?x)导致一些错误出玎ͼ不是大部分会(x)(g)到真实d的?/p>
3.1 一?CSS d的正则表辑ּ /((\%3C)|<)((\%2F)|/)*[a-z0-9\%]+((\%3E)|>)/ix 解释: Snort 规则: 跨站脚本同样可以使用<img src=>技术。现行默认的snort规则可以被轻易避开?/p>
3.2章节提供?jin)防止这U技术的Ҏ(gu)?/strong> 3.2 "<img src" CSS d正则表达?/p>
/((\%3C)|<)((\%69)|i|(\%49))((\%6D)|m|(\%4D))((\%67)|g|(\%47))[^
]+((\%3E)|>)/I 解释: 3.3 CSS d的极端的正则表达?/p>
/((\%3C)|<)[^ ]+((\%3E)|>)/I 解释: q个规则单寻?lt;+除换行符外的M字符+>。由于你的web服务器和web应用E序的构Ӟq个规则可能产生一些错误。但它能保证
捉住MCCS或者类似CSS的攻凅R?/p>
ȝ: ?
q篇文章中,我们提出?jin)不同种cȝ正则表达式规则来(g)SQL注入和跨站脚本攻凅R有些规则简单而极端,一个潜在的d都将提高警惕。但q些极端的规则可
能导致一些主动的错误。考虑到这点,我们修改?jin)这些简单的规则Q利用了(jin)另外的样式,他们可以(g)查的更准些。在q些|络应用成的d(g)中Q我们推荐将q?
些作试你I(yng)DS或日志分析方法的L(fng)。再l过几次修改后,在你Ҏ(gu)常网交易部分的非恶意应答q行评估以后Q你应该可以准备的检那些攻M(jin)?strong>
q篇是翻译老外的文章,css 跨站d只需qo(h)掉html括号即可,擦,又被专家们忽(zhn)了(jin)Q网上盛传的 完整的XSS wrom安全(g)实例示范,W一ơ就把标记对都过滤了(jin)Q下面竟然还用标记测试,啥逻辑Q我只想知道是怎么成功的,搞笑Q误?/p>
加入上述正则表达式的新的Snort规则如下:
where num_value3=some_user_supplied_number
w* - 零个或多个字W或者下划线?
(\%27)|’ - 单引h它的hex{倹{?
(\%6 F)|o|(\%4 F))((\%72)|r|-(\%52) Q?#8216;or’的大写以及(qing)它的hex{倹{?/p>
union - union关键?/p>
exec - h执行储存或扩展储存过E的关键?
(s|+)+ - 一个或多个的空白或它们的http{值编?
(s|x) p- ‘sp’?#8216;xp’字母用来辨认储存或扩展储存过E?
w+ - 一个或多个字符或下划线来匹配过E的名称
((\%3C)|<) Q检?lt;和它hex{?
((\%2F)|/)*Q结束标{?或它?hex{?
[a-z0-9\%]+ Q检查标{N的字母或它hex{?
((\%3E)|>) Q检?gt;或它的hex{?/p>
alert tcp $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS (msg:"NII
Cross-site scripting attempt"; flow:to_server,established;
pcre:"/((\%3C)|<)((\%2F)|/)*[a-z0-9\%]+((\%3E)|>)/i";
classtype:Web-application-attack; sid:9000; rev:5;)
(\%3 C)|<) -<或它的hex{?
(\%69)|i|(\%49))((\%6D)|m|(\%4D))((\%67)|g|(\%47)
-’img’字母或它的大写hex{值的变化l合
[^ ]+ -除了(jin)换行W以外的M跟随<img的字W?
(\%3E)|>) ->或它的hex{?/p>
for (i = 0; i < 256; i++) { crc = i; for (j = 0; j < 8; j++) { if (crc & 1) crc = (crc >> 1) ^ 0xEDB88320; else crc >>= 1; } crc32tbl[i] = crc; } |
temp = (oldcrc ^ abyte) & 0x000000FF; crc = (( oldcrc >> 8) & 0x00FFFFFF) ^ crc32tbl[temp]; return crc; |
#include "resource.h" #define IDC_BUTTON_OPEN 3000 #define IDC_EDIT_INPUT 3001 #define IDC_STATIC -1 LC_DIALOG DIALOGEX 10, 10, 195, 60 STYLE DS_SETFONT | DS_CENTER | WS_MINIMIZEBOX | WS_VISIBLE | WS_CAPTION | WS_SYSMENU CAPTION "lc’s assembly framework" FONT 9, "?hu)?, 0, 0, 0x0 BEGIN LTEXT "误入一个字W串Q区分大写Q:(x)",IDC_STATIC,11,7,130,10 EDITTEXT IDC_EDIT_INPUT,11,20,173,12,ES_AUTOHSCROLL DEFPUSHBUTTON "Ca&lc",IDC_BUTTON_OPEN,71,39,52,15 END |
;*************************************************************** ;花指令实? ;作者:(x)|聪 ;日期Q?002-8-21 ;*************************************************************** .386 .model flat, stdcall option casemap:none include "masm32"include"windows.inc include "masm32"include"kernel32.inc include "masm32"include"user32.inc includelib "masm32"lib"kernel32.lib includelib "masm32"lib"user32.lib .data szText db "嘿嘿Q这是一个花指o(h)E序……", 0 szCaption db "花指令演C?by LC 2002-8-21", 0 .code main: jmp Do_It Do_It: invoke MessageBox, NULL, addr szText, addr szCaption, MB_OK invoke ExitProcess, 0 end main |
+++++++++++++++++++ ASSEMBLY CODE LISTING ++++++++++++++++++ //********************** Start of Code in Object .text ************** Program Entry Point = 00401000 (hua.exe File Offset:00001600) //******************** Program Entry Point ******** :00401000 EB00 jmp 00401002 * Referenced by a (U)nconditional or ?onditional Jump at Address: |:00401000(U) | :00401002 6A00 push 00000000 * Possible StringData Ref from Data Obj ->"花指令演C?by LC 2002-8-21" | :00401004 681F304000 push 0040301F * Possible StringData Ref from Data Obj ->"嘿嘿Q这是一个花指o(h)E序……" | :00401009 6800304000 push 00403000 :0040100E 6A00 push 00000000 * Reference To: USER32.MessageBoxA, Ord:01BBh | :00401010 E80D000000 Call 00401022 :00401015 6A00 push 00000000 * Reference To: KERNEL32.ExitProcess, Ord:0075h | :00401017 E800000000 Call 0040101C |
"嘿嘿Q这个是一个花指o(h)E序……" "花指令演C?by LC 2002-8-21" |
;*************************************************************** ;花指令实? ;作者:(x)|聪 ;日期Q?002-8-21 ;*************************************************************** .386 .model flat, stdcall option casemap:none include "masm32"include"windows.inc include "masm32"include"kernel32.inc include "masm32"include"user32.inc includelib "masm32"lib"kernel32.lib includelib "masm32"lib"user32.lib .data szText db "嘿嘿Q这是一个花指o(h)E序……", 0 szCaption db "花指令演C?by LC 2002-8-21", 0 .code main: jz Do_It ;注意q里和第一个实验中的源E序的区?br /> jnz Do_It ;注意q里和第一个实验中的源E序的区?br /> Do_It: invoke MessageBox, NULL, addr szText, addr szCaption, MB_OK end main |
+++++++++++++++++++ ASSEMBLY CODE LISTING ++++++++++++++++++ //********************** Start of Code in Object .text ************** Program Entry Point = 00401000 (hua.exe File Offset:00001600) //******************** Program Entry Point ******** :00401000 7402 je 00401004 :00401002 7500 jne 00401004 * Referenced by a (U)nconditional or ?onditional Jump at Addresses: |:00401000?, :00401002? | :00401004 6A00 push 00000000 * Possible StringData Ref from Data Obj ->"花指令演C?by LC 2002-8-21" | :00401006 681F304000 push 0040301F * Possible StringData Ref from Data Obj ->"嘿嘿Q这是一个花指o(h)E序……" | :0040100B 6800304000 push 00403000 :00401010 6A00 push 00000000 * Reference To: USER32.MessageBoxA, Ord:01BBh | :00401012 E801000000 Call 00401018 |
;*************************************************************** ;花指令实? ;作者:(x)|聪 ;日期Q?002-8-21 ;*************************************************************** .386 .model flat, stdcall option casemap:none include "masm32"include"windows.inc include "masm32"include"kernel32.inc include "masm32"include"user32.inc includelib "masm32"lib"kernel32.lib includelib "masm32"lib"user32.lib .data szText db "嘿嘿Q这是一个花指o(h)E序……", 0 szCaption db "花指令演C?by LC 2002-8-21", 0 .code main: jz Do_It ;注意q里和第一个实验中的源E序的区?br /> jnz Do_It ;注意q里和第一个实验中的源E序的区?br /> db 0E8h ;注意q里和第二个实验中的源程序的区别 Do_It: invoke MessageBox, NULL, addr szText, addr szCaption, MB_OK invoke ExitProcess, 0 end main |
+++++++++++++++++++ ASSEMBLY CODE LISTING ++++++++++++++++++ //********************** Start of Code in Object .text ************** Program Entry Point = 00401000 (hua.exe File Offset:00001600) //******************** Program Entry Point ******** :00401000 7403 je 00401005 :00401002 7501 jne 00401005 :00401004 E86A00681D call 1DA81073 :00401009 304000 xor byte ptr [eax+00], al * Possible StringData Ref from Data Obj ->"嘿嘿Q这是一个花指o(h)E序……" | :0040100C 6800304000 push 00403000 :00401011 6A00 push 00000000 * Reference To: USER32.MessageBoxA, Ord:01BBh | :00401013 E80E000000 Call 00401026 :00401018 6A00 push 00000000 * Reference To: KERNEL32.ExitProcess, Ord:0075h | :0040101A E801000000 Call 00401020 |
"嘿嘿Q这是一个花指o(h)E序……" |
;*************************************************************** ;花指令实? ;作者:(x)|聪 ;日期Q?002-8-21 ;*************************************************************** .386 .model flat, stdcall option casemap:none include "masm32"include"windows.inc include "masm32"include"kernel32.inc include "masm32"include"user32.inc includelib "masm32"lib"kernel32.lib includelib "masm32"lib"user32.lib .data szText db "嘿嘿Q这是一个花指o(h)E序……", 0 szCaption db "花指令演C?by LC 2002-8-21", 0 .code main: jz Do_It ;注意q里和第一个实验中的源E序的区?br /> jnz Do_It ;注意q里和第一个实验中的源E序的区?br /> db 0E8h ;注意q里和第二个实验中的源程序的区别 Do_It: lea eax, szText ;注意q里和第三个实验中的源程序的区别 lea ebx, szCaption ;注意q里和第三个实验中的源程序的区别 invoke MessageBox, NULL, eax, ebx, MB_OK ;注意q里和第三个实验中的源程序的区别 invoke ExitProcess, 0 end main |
+++++++++++++++++++ ASSEMBLY CODE LISTING ++++++++++++++++++ //********************** Start of Code in Object .text ************** Program Entry Point = 00401000 (hua.exe File Offset:00001600) //******************** Program Entry Point ******** :00401000 7403 je 00401005 :00401002 7501 jne 00401005 :00401004 E88D050030 call 30401596 :00401009 40 inc eax :0040100A 008D1D1D3040 add byte ptr [ebp+40301D1D], cl :00401010 006A00 add byte ptr [edx+00], ch :00401013 53 push ebx :00401014 50 push eax :00401015 6A00 push 00000000 * Reference To: USER32.MessageBoxA, Ord:01BBh | :00401017 E80E000000 Call 0040102A :0040101C 6A00 push 00000000 * Reference To: KERNEL32.ExitProcess, Ord:0075h | :0040101E E801000000 Call 00401024 |
/**
* 用于的 Browser 不缓存页面的qo(h)?br />
*/
public class ForceNoCacheFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException
{
((HttpServletResponse) response).setHeader("Cache-Control","no-cache");
((HttpServletResponse) response).setHeader("Pragma","no-cache");
((HttpServletResponse) response).setDateHeader ("Expires", -1);
filterChain.doFilter(request, response);
}
public void destroy()
{
}
public void init(FilterConfig filterConfig) throws ServletException
{
}
}
二、检用h否登陆的qo(h)?/p>
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.List;
import java.util.ArrayList;
import java.util.StringTokenizer;
import java.io.IOException;
/**
* 用于(g)用h否登陆的qo(h)器,如果未登录,则重定向到指的登录页?lt;p>
* 配置参数<p>
* checkSessionKey 需(g)查的?Session 中保存的关键?lt;br/>
* redirectURL 如果用户未登录,则重定向到指定的面QURL不包?ContextPath<br/>
* notCheckURLList 不做(g)查的URL列表Q以分号分开Qƈ?URL 中不包括 ContextPath<br/>
*/
public class CheckLoginFilter
implements Filter
{
protected FilterConfig filterConfig = null;
private String redirectURL = null;
private List notCheckURLList = new ArrayList();
private String sessionKey = null;
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException
{
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
HttpSession session = request.getSession();
if(sessionKey == null)
{
filterChain.doFilter(request, response);
return;
}
if((!checkRequestURIIntNotFilterList(request)) && session.getAttribute(sessionKey) == null)
{
response.sendRedirect(request.getContextPath() + redirectURL);
return;
}
filterChain.doFilter(servletRequest, servletResponse);
}
public void destroy()
{
notCheckURLList.clear();
}
private boolean checkRequestURIIntNotFilterList(HttpServletRequest request)
{
String uri = request.getServletPath() + (request.getPathInfo() == null ? "" : request.getPathInfo());
return notCheckURLList.contains(uri);
}
public void init(FilterConfig filterConfig) throws ServletException
{
this.filterConfig = filterConfig;
redirectURL = filterConfig.getInitParameter("redirectURL");
sessionKey = filterConfig.getInitParameter("checkSessionKey");
String notCheckURLListStr = filterConfig.getInitParameter("notCheckURLList");
if(notCheckURLListStr != null)
{
StringTokenizer st = new StringTokenizer(notCheckURLListStr, ";");
notCheckURLList.clear();
while(st.hasMoreTokens())
{
notCheckURLList.add(st.nextToken());
}
}
}
}
三、字W编码的qo(h)?/p>
import javax.servlet.*;
import java.io.IOException;
/**
* 用于讄 HTTP h字符~码的过滤器Q通过qo(h)器参数encoding指明使用何种字符~码,用于处理Html Formh参数的中文问?br />
*/
public class CharacterEncodingFilter
implements Filter
{
protected FilterConfig filterConfig = null;
protected String encoding = "";
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException
{
if(encoding != null)
servletRequest.setCharacterEncoding(encoding);
filterChain.doFilter(servletRequest, servletResponse);
}
public void destroy()
{
filterConfig = null;
encoding = null;
}
public void init(FilterConfig filterConfig) throws ServletException
{
this.filterConfig = filterConfig;
this.encoding = filterConfig.getInitParameter("encoding");
}
}
四、资源保护过滤器
package catalog.view.util; import javax.servlet.Filter; import javax.servlet.FilterConfig; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.util.Iterator; import java.util.Set; import java.util.HashSet; // import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * This Filter class handle the security of the application. ** It should be configured inside the web.xml. * * @author Derek Y. Shen */ public class SecurityFilter implements Filter { //the login page uri private static final String LOGIN_PAGE_URI = "login.jsf"; //the logger object private Log logger = LogFactory.getLog(this.getClass()); //a set of restricted resources private Set restrictedResources; /** * Initializes the Filter. */ public void init(FilterConfig filterConfig) throws ServletException { this.restrictedResources = new HashSet(); this.restrictedResources.add("/createProduct.jsf"); this.restrictedResources.add("/editProduct.jsf"); this.restrictedResources.add("/productList.jsf"); } /** * Standard doFilter object. */ public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { this.logger.debug("doFilter"); String contextPath = ((HttpServletRequest)req).getContextPath(); String requestUri = ((HttpServletRequest)req).getRequestURI(); this.logger.debug("contextPath = " + contextPath); this.logger.debug("requestUri = " + requestUri); if (this.contains(requestUri, contextPath) && !this.authorize((HttpServletRequest)req)) { this.logger.debug("authorization failed"); ((HttpServletRequest)req).getRequestDispatcher(LOGIN_PAGE_URI).forward(req, res); } else { this.logger.debug("authorization succeeded"); chain.doFilter(req, res); } } public void destroy() {} private boolean contains(String value, String contextPath) { Iterator ite = this.restrictedResources.iterator(); while (ite.hasNext()) { String restrictedResource = (String)ite.next(); if ((contextPath + restrictedResource).equalsIgnoreCase(value)) { return true; } } return false; } private boolean authorize(HttpServletRequest req) { //处理用户d /* UserBean user = (UserBean)req.getSession().getAttribute(BeanNames.USER_BEAN); if (user != null && user.getLoggedIn()) { //user logged in return true; } else { return false; }*/ } }
1、当用户q行的是Refresh/Reload/Back/Forward操作、以?qing)?span style="font-size: 9pt; background: #d9d9d9; color: #333333">Back?span style="font-size: 9pt; background: #d9d9d9; color: #333333">Submit操作Ӟ仅仅?span style="font-size: 9pt; background: #d9d9d9; color: #333333">reloading先前的结果页?/p>
2、当用户重复提交同一个Q务操作时,后台服务接收q处理第一ơ提交的dQ后面提交不起作用(不{向也不提C)(j)?/p>
3、该功能h公用性?/p>
基本形成思\Q?/strong>
1、在basic filter中实现公用?/p>
if(true){//问题1Q如何确定是否ؓ(f)重复提交
...
chain.doFilter(request,response);
}else{
//问题2Q如何实C转向、不提示也不昄I白?/p>
}
2、网上资料概?/p>
a、提交表单后按钮变灰/隐藏提交按钮
b、在js里设|全局变量Q提交后修改该变量的|依据变量的值判断是否重复提?/p>
var flag=true;
function checkForm(){
if (flag==false){
return;
}
flag=false;
document.form1.submit();
}
c?span style="font-size: 9pt; background: #d9d9d9; color: #333333">struts Q?span style="font-size: 9pt; background: #d9d9d9; color: #333333">webwork没有扑ֈq个资料Q?/p>
//验证事务控制令牌,<html:form >?x)自动根?span style="font-size: 9pt; background: #d9d9d9; color: #333333">session中标识生成一个隐?span style="font-size: 9pt; background: #d9d9d9; color: #333333">input代表令牌Q防止两ơ提?/p>
?span style="font-size: 9pt; background: #d9d9d9; color: #333333">action中:(x)
//<input type="hidden" name="org.apache.struts.taglib.html.TOKEN" value="6aa35341f25184fd996c4c918255c3ae">
if (!isTokenValid(request))
errors.add(ActionErrors.GLOBAL_ERROR,
new ActionError("error.transaction.token"));
resetToken(request); //删除session中的令牌
action有这L(fng)一个方法生成o(h)牌华
protected String generateToken(HttpServletRequest request) {
HttpSession session = request.getSession();
try {
byte id[] = session.getId().getBytes();
byte now[] =
new Long(System.currentTimeMillis()).toString().getBytes();
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(id);
md.update(now);
return (toHex(md.digest()));
} catch (IllegalStateException e) {
return (null);
} catch (NoSuchAlgorithmException e) {
return (null);
}
}
d、用户用浏览器Ӟ可以l常使用向后的按钮,因此有可能重复提交一个他们已l提交过?span style="font-size: 9pt; background: #d9d9d9; color: #333333">formQ这样就?x)带来一个重复事务处理的问题。同P一个用户也可能在接收到一个确认的面之前按下停止的按钮,接着再次提交同一?span style="font-size: 9pt; background: #d9d9d9; color: #333333">form。对于这些情况,我们都想跟踪q且止q些重复的提交,我们可以使用一个控?span style="font-size: 9pt; background: #d9d9d9; color: #333333">servlet来提供一个控制点Q以解决q个问题?/p>
同步记号Q?span style="font-size: 9pt; background: #d9d9d9; color: #333333">Synchronizer (or Dvu) TokenQ?/p>
q个{略是ؓ(f)?jin)解决重复?span style="font-size: 9pt; background: #d9d9d9; color: #333333">form提交问题。一个同步的记号被设|在一个用L(fng)Session中,q且包含在返回到客户的每一?span style="font-size: 9pt; background: #d9d9d9; color: #333333">form中。当form被提交时Q?span style="font-size: 9pt; background: #d9d9d9; color: #333333">form中的同步标记和Session中的同步标记作对比。在form首次提交的时候,q两个标记应该是一L(fng)。如果标C一P那么?span style="font-size: 9pt; background: #d9d9d9; color: #333333">form׃(x)止提交Q一个错误就?x)返回给用户。在用户提交一?span style="font-size: 9pt; background: #d9d9d9; color: #333333">formӞ如果按下览器中的后退按钮q尝试重新提交同一?span style="font-size: 9pt; background: #d9d9d9; color: #333333">formӞ标记׃(x)出现不匹配的现象?/p>
另一斚wQ如果两个标记值匹配,那么我们可以确信整个流E是正确的。在q种情况下,Session中的标记值就?x)被修改Z个新的|同时允许提交该form? 你也可以使用q个{略来控制对某些面的直接访问,好象上面资源保护中描述的一栗例如,假设一个用户将某个应用的页面A收藏到收藏夹中,而页面A只允?dng)R过面B和C讉K。当用户直接通过收藏Ҏ(gu)讉K面AQ这旉面的讉K序是不正的Q这样同步标记将处在一个不同步的状态,或者它Ҏ(gu)׃存在。不论怎样Q访问都被禁止了(jin)? e、做一个hidden框,名字自己定,提交后得到这个值放入sessionQ提交前判断session是否为空 解决Ҏ(gu)Q? 1、后台公q中实现前台的Form中自动生成两个hidden文本功能Q一个是作page是否重复提交判断Qƈql自动附上关键|如struts采用的方案)(j)Q另一个作为button是否重复提交判断Qstruts中好像没有)(j)。由后台公共cd现界面两个hidden text自动生成的好处在于公用性? 2、在basic filter中根据两个hidden text值判断是否ؓ(f)重复提交? 3、javascript中作一个公共方法,实现功能Q如果需要判断是否重复提交,qW二个hidden text附上关键|q该功能不可用?. 个h感想Q我怿未来该功能一定会(x)被服务器集成Q而不再由开发h员进行编?
----------------------------------------CZ代码----------------------------------------------------
W一Q对于不支持POST的,可以单的使用如下代码
if ("POST".equals(request.getMethod())) ...{
// 正常q行
}else...{
// 异常h
out.print("异常讉K");
return;
}
如果是servlet, 可以doGetҎ(gu)直接q回Q不q行处理p?br />
public void doGet(HttpServletRequest request, HttpServletResponse response) ...{
return;
}
public void doPost(HttpServletRequest request, HttpServletResponse response) ...{
// 正常q行操作
}
q可以采用特定的标志来区分,比如
<form><input type="hidden" name="action" value="insert"/></form>
E序里这样判?br />
if ("POST".equals(request.getMethod()) && ("insert".equals(request.getParameter("action")))) ...{
// 正常q行
}else...{
// 异常h
out.print("异常讉K");
return;
}
W二Q判断提交的来源referer,代码如下
if ("POST".equals(request.getMethod())) ...{
String referer = request.getHeader("referer");
if (referer == null || !referer.startsWith("http://"+request.getServerName())) ...{
// 非法来源
return;
}
// 正常q行
}else...{
// 异常h
out.print("异常讉K");
return;
}
W三 防止重复提交的hashCode
在表单显C页?br />
//生成一个formhash,法可以自己定,不随侉K复就可以?br />
String formhash = MD5.encode(Long.toString(new Date().getTime()));
//d当前session里面的hashCode集合Q此处用了(jin)SetQ方便判断?br />
Set<String> formhashSession = (Set<String>) session.getAttribute("formhashSession");
if (formhashSession == null) ...{
formhashSession = new HashSet<String>();
}
// (g)重复问?br />
while (formhashSession.contains(formhash)) ...{
formhash = MD5.encode(Long.toString(new Date().getTime()));
}
// 保存到session里面
formhashSession.add(formhash);
// 保存
session.setAttribute("formhashSession", formhashSession);
表单里面增加如下字段
<input type="hidden" name="formhash" id="formhash" value="<%=formhash%>" />
在表单提交页面进行如下处?br />
// 拿到表单的formhash
String formhash = upload.getParameter("formhash");
// 拿到session里面的集?br />
Set<String> formhashSession = (Set<String>) session.getAttribute("formhashSession");
// 如果没有Q则是重复提交,或者非法提?br />
if (formhashSession == null || !formhashSession.contains(formhash)) ...{
out.println("请不要重复提交!");
return;
}
// 下面q行其它的操?br />
//
// 最?如果操作成功,从session里面把这个formhash 删掉Q?br />
// 以免用户填写了(jin)某个字段Q造成表单无法再次提交
formhashSession.remove(formhash);
session.setAttribute("formhashSession", formhashSession);
目前没有证据表明有Gmail用户的密码被盗。Google公司斚w表示Q在受到d数小时后Q公司就ȀzM(jin)Gmail新的加密层,而且加强?jin)数?中心(j)的安全性,q进一步加Z(jin)其网上服务与用户计算Z间通信q接的安全。但是,有安全分析h员指出,d者在d?jin)内部密码系l之后,有可能在Gaia pȝ和Google全球数据中心(j)中安装木马,只不q在Google的安全专家获知受d之后Q这变得非常困难。另外,d者在获取?jin)系l的源代码ƈ?jin)解?pȝq作机理之后Q也有可能(虽然可能性不大)(j)发现Googleq(sh)知道的安全漏z,q种隐?zhn)很o(h)安全专家头痛?/p>
文中q解释了(jin)此次Google所受攻ȝ详细q程Q?/p>
1. d者首先通过微YMSNl一个Google中国的员工A发去一条即时消息?/p>
2. q个员工在不知情的情况下点击?jin)其中的|址Qƈ讉K?#8220;已污染的”|站Qd者获得了(jin)讉KA使用的计机的权限?/p>
3. d者由此访问了(jin)Google公司的内部目录系l(名ؓ(f)MomaQ,其中保存着所有Google员工的工作情况,包括具体员工的信息?/p>
4. 在查扑ֈ?jin)位于Google国总部的Gaia软g开发者的名字之后Q他们而首先尝试访问开发者的工作?sh)脑?/p>
5. 然后使用?jin)一q串复杂的技术获取了(jin)Gaiapȝ源代码库的访问权限?/p>
6. 接下来,他们把偷到的软g传输C计算服务提供商Rackspace的计机上,此后再传到哪里,׃再ؓ(f)人所知?/p>
文中_(d)Gaiapȝ目前仍然在用,现在的正式名U被UCؓ(f)Single Sign-On?/p>
本周一Google的高拒l对此进行评论,说其中暴露的安全问题早已l解冟?/p>
有安全专家表C,新的dl节很可能增加h们对云计安全的担心(j)。由于v量的信息现在被相寚w中存攑֜一些计机pȝ中,单点被攻破就可能带来N 性的损失?/p>
参数很多,一般我们用 -c ?-n 参数可以了(jin). 例如:
./ab -c 1000 -n 1000 http://127.0.0.1/index.php
q个表示同时处理1000个请求ƈq行1000ơindex.php文g.
#/usr/local/xiaobai/apache2054/bin/ab -c 1000 -n 1000 http://127.0.0.1/index.html.zh-cn.gb2312
This is ApacheBench, Version 2.0.41-dev <$Revision: 1.121.2.12 $> apache-2.0
Copyright (c) 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Copyright (c) 1998-2002 The Apache Software Foundation, http://www.apache.org/
Benchmarking 127.0.0.1 (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Finished 1000 requests
Server Software: Apache/2.0.54
//q_apache 版本2.0.54
Server Hostname: 127.0.0.1
//服务器主机名
Server Port: 80
//服务器端?/font>
Document Path: /index.html.zh-cn.gb2312
//试的页面文?/font>
Document Length: 1018 bytes
//文档大小
Concurrency Level: 1000
//q发?br />
Time taken for tests: 8.188731 seconds
//整个试持箋(hu)的时?/font>
Complete requests: 1000
//完成的请求数?/font>
Failed requests: 0
//p|的请求数?/font>
Write errors: 0
Total transferred: 1361581 bytes
//整个场景中的|络传输?/font>
HTML transferred: 1055666 bytes
//整个场景中的HTML内容传输?br />
Requests per second: 122.12 [#/sec] (mean)
//大家最兛_(j)的指标之一Q相当于 LR 中的 每秒事务?/span> Q后面括号中?/span> mean 表示q是一个^均?/span>
Time per request: 8188.731 [ms] (mean)
//大家最兛_(j)的指标之二,相当?/span> LR 中的 q_事务响应旉 Q后面括号中?/span> mean 表示q是一个^均?/span>
Time per request: 8.189 [ms] (mean, across all concurrent requests)
//每个h实际q行旉的^均?/font>
Transfer rate: 162.30 [Kbytes/sec] received
//q_每秒|络上的量Q可以帮助排除是否存在网l流量过大导致响应时间g长的问题
Connection Times (ms)
min mean[+/-sd] median max
Connect: 4 646 1078.7 89 3291
Processing: 165 992 493.1 938 4712
Waiting: 118 934 480.6 882 4554
Total: 813 1638 1338.9 1093 7785
//|络上消耗的旉的分解,各项数据的具体算法还?sh)是很清?/span>
Percentage of the requests served within a certain time (ms)
50% 1093
66% 1247
75% 1373
80% 1493
90% 4061
95% 4398
98% 5608
99% 7368
100% 7785 (longest request)
//整个场景中所有请求的响应情况。在场景中每个请求都有一个响应时_(d)其中50Q的用户响应旉于1093 毫秒Q?0Q?的用户响应时间小?247 毫秒Q最大的响应旉于7785 毫秒
׃对于q发hQcpu实际上ƈ不是同时处理的,而是按照每个h获得的时间片逐个轮{处理的,所以基本上W一个Time per request旉U等于第二个Time per request旉乘(sh)q发h?/font>