针对PE框架中常见的以下Command分析其功能实现。这也是web开发中很常见、通用的功能,对它们进行学习和理解很重要。
- requestCheckCommand UGC(用户提交内容)和谐,防止XSS
- loginControlCommand 防撞库
- tokenControlCommand 防重复提交,防CSRF(跨站请求伪造)
- tokenControlVercodeCommand 图形验证码校验
- phoneTokenControlCommand 短信验证码校验
UGC和谐,防止XSS攻击
对用户的输入的数据进行处理很重要,这里的目的是防止xss攻击,其实另一个很重要的目的没考虑到:敏感词过滤。
防止xss攻击的手段就是对字段中的一些危险关键字进行过滤,如以下字段将被替换为""
:
<param name="js1"><![CDATA[<script]]></param>
<param name="js2"><![CDATA[<img]]></param>
...
防撞库
撞库通常是对采用弱密码的用户进行试探性登陆,因为前几年的拖库事件,导致现在更多是对不同网站相同用户名与密码的用户进行试探性登陆,成功率也大大增加。防止撞库的前端手段通常是采用验证码,此外后端也需要提供手段处理。
在PE中,每次密码错误导致的登陆失败,都会将UserId及其失败计数记录到Failure Map中。要求阈值次失败次数前,两次登陆间隔不低于一定时间;阈值次失败次数后,两次登陆间隔不低于更长的时间。伪代码表示为:
if(failtimes<threshold){//e.g 5 if(submitTime<lastSubmitTime+retryInterval){//e.g 30s return false;//failure } }else{ if(submitTime<lastSubmitTime+failureInterval){//e.g 30min return false; } }
防重复提交,图形验证码,短信验证码
防重复提交、图形验证码、短信验证码的逻辑其实差不多:在进行提交操作前从服务器获取一段随机的字符串称为“验证码”,提交后服务器将对客户提交的验证码字段进行匹配,确认其有效。
不同点在于,防重复提交操作对用户是透明的,用户并不需要参与这个过程;图形验证码需要根据验证码生成图片,用户识别图片并填入验证码;短信验证码需要调用短信服务器发送短信,用户接受短信后填入验证码。
PE框架这三种操作的验证码生成和校验进行了统一的抽象,由TockenManager
进行统一管理,定义了以下属性:
- maxEntryNumber 最多存储的验证码个数
- delayTime 验证码有效期
- tokenListName 保存在session中的验证码列表名称
- tokenName 验证码名称,用于从data中提取验证码
- tokenLength 验证码长度
- ignoreCase 是否忽略大小写
- chars 随机生成验证码的字符字典
不同类型的验证码可以通过提供不同的参数来自定义这些属性,实现自己的逻辑。
Token
类表示具体的验证码,包括验证码id,生成时间。
public class Token{ long accessDate; String uniqueId; }
Token
存储在tokenList
中,而tokenList
则存储在session
中。TockenList
类表示tockenList
,提供了以下方法:
- getNextTokenId() 通过
SecureRandom
生成的随机数,从chars中随机获取字符生成验证码 - addToken() 添加Tocken,这可能会移除很老的Tocken
- get(tokenId) 获取Tocken,这将移除该Tocken
防固定会话Id攻击
如果服务器接收通过URL的查询参数传递过来的sessionId
,并且会话期间sessionId
不会改变,那么就会发生如下的攻击场景:
假设A为攻击者,B为受害者,网站为银行。A访问银行网站,得到sessionId=AAAAAA,这保证了该sessionId的有效性。然后A给B发送邮件:我行现推出xxx产品,年利率高达20%,快来体验http://bank.com/sessionId=AAAAAA
,B点击并输入账号密码成功登陆。此时为AAAAAA的sessionId与B的账户是关联的,A以该sessionId访问该银行网站,就能冒充A。
为了防止这种攻击,用户成功登陆后必须更改sessionId,再关联用户信息。PE中也是采用这种方式。