5.1 敏感数据传输
应用程序中的敏感信息传输应使用SSL做传输层加密代码示例。
代码示例:web.xml
<init-param>
<param-name>tp.cas.client.filter.loginUrl</param-name>
<param-value>http://www.xxx.com/login</param-value>
</init-param>
//某应用程序的配置文件web.xml,其中配置了登录URL,可看到登录过程未使用SSL,存在安全风险
5.2 敏感数据加密
应用程序应对交易数据进行签名,以防交易信息被攻击者篡改对用户造成损失。
代码示例:
public clas SavToTimAction extends IbsTwoPhaseAction implements PageLoader,ApplicationContextAware
{
...
public void submit(Context context) throws PeException {
super.submit(context); //获取到表单数据后,直接提交,并未进行签名校验
}
...
}
//以上代码段未对客户端的请求进行签名验证,导致敏感数据可以被任意篡改
敏感数据加密安全编码规范
对于重要的数据,应对数据进行加密处理后传输。
public clas SavToTimAction extends IbsTwoPhaseAction implements PageLoader,ApplicationContextAware
{
...
public void submit(Context context) throws PeException {
//对重要信息使用3DES等加密算法加密
context.CardNo=3DES.Encrypt(context.CardNo);
super.submit(context); //获取到表单数据后,直接提交,并未进行签名校验
}
...
}
5.3 交易数据重放
对于交易数据,代码中应检验每次客户端提交的数据的唯一性,如使用时间戳、验证码等,防止攻击者将截获到的数据包重放造成用户财产损失。
代码示例:
public clas SavToTimAction extends IbsTwoPhaseAction implements PageLoader,ApplicationContextAware
{
...
public void submit(Context context) throws PeException {
super.submit(context); //获取到表单数据后,直接提交,并未进行唯一性检验
}
...
}
//代码中未对客户端提交的数据做唯一性检验就将数据提交至核心进行处理,攻击者将截获的交易数据包重放就可对使该账户造成多次交易。
5.4 密码复杂度
应用程序的密码设置功能应对用户设置的密码进行复杂度检验,避免用户输入弱口令。
代码示例:
public class EBankPwdModifyAction extends IbsTwoPhaseAction {
...
public void prepare(Context context) throws PeException {
...
String passwordOld = (String) context.getData("PasswordOld");
String passwordNew = (String) context.getData("PasswordNew");
String passwordConfirm = (String) context.getData("PasswordConfirm");
if (passwordOld.equals(passwordNew)) {
throw new ValidationException("validation.password.match.old");
}
if (!passwordNew.equals(passwordConfirm)) {
throw new ValidationException("validation.password.new.confirm.notequal");
}
Map paramMap = new HashMap();
paramMap.put(Constants.USER_SEQ, userSeq);
Map result = (Map) getSqlMap().queryForObject("setting.queryUserInfo",paramMap);
if (result == null) {
throw new ValidationException("validation.user.notexist");
}
...
}
public void submit(Context context) throws PeException {
PerUser user = (PerUser) context.getUser();
Map paramMap = context.getDataMap();
//更新密码
int i = getSqlMap().update("setting.updateUserPassword", paramMap);
String passwordNew = (String) context.getData("PasswordNew");
if (i > 0) {
user.setPassword(passwordNew);
}
...
}
}
//在用户提交修改密码请求时,未对密码复杂度进行校验,导致用户可以设置弱口令
5.5 修改密码的逻辑
应用程序中修改密码的功能应当先对旧密码进行验证,再进行修改密码操作。
在应用程序中对旧密码进行了验证的情况下,对修改密码的次数也需要限制,防止攻击者利用该功能达到暴力破解旧密码的目的。
代码示例:
public class EBankPwdModifyAction extends IbsTwoPhaseAction {
...
public void prepare(Context context) throws PeException {
...
String passwordNew = (String) context.getData("PasswordNew");
String passwordConfirm = (String) context.getData("PasswordConfirm");
if (!passwordNew.equals(passwordConfirm)) {
throw new ValidationException("validation.password.new.confirm.notequal");
}
Map paramMap = new HashMap();
paramMap.put(Constants.USER_SEQ, userSeq);
Map result = (Map) getSqlMap().queryForObject("setting.queryUserInfo",paramMap);
if (result == null) {
throw new ValidationException("validation.user.notexist");
}
...
}
public void submit(Context context) throws PeException {
PerUser user = (PerUser) context.getUser();
Map paramMap = context.getDataMap();
//更新密码
int i = getSqlMap().update("setting.updateUserPassword", paramMap);
String passwordNew = (String) context.getData("PasswordNew");
if (i > 0) {
user.setPassword(passwordNew);
}
...
}
}
//在修改密码前未对旧密码进行校验,攻击者可通过CSRF等方式恶意修改其他用户的密码
5.6 重置密码的逻辑
应用程序应注意重置密码的逻辑,避免出现逻辑漏洞导致重置其他用户密码等漏洞。
代码示例:
//发送验证码代码
public void sendSecondPswNoLogin(HttpServletRequest request,HttpServletResponse response) throws BusiException, HandlerException,UnifyInvokerException
{
BaseSessionHandler handler = getHandler(request);
String code = handler.createSignCode();
String phone_id = request.getParameter("phone_id");
request.getSession().setAttribute("PHONENUM", phone_id);
...
}
//校验验证码并重置密码代码
public String change_password(HttpServletRequest request) throws HandlerException {
String newpassword = request.getParameter("newpassword");
String pwdNewConfirm = request.getParameter("pwdNewConfirm");
if(!pwdNewConfirm.equals(newpassword)) {
...
}
String encrypt_newpassword = UnifyInvokeHelper.do_encryptstr(newpassword);
HashMap parapMap = new HashMap();
parapMap.put("phoneid", request.getParameter("phone_id"));
parapMap.put("newpassword", encrypt_newpassword);
UnifyInvokeService.getUnifyInvokeService().processInvokeByBusi(parapMap);
...
}
//修改密码的phone_id直接从request中读入,没有检查与之前写入session的phone_id是否一致,攻击者可以在URL中将phone_id设置为其他用户的手机号码,从而实现重置任意用户密码
5.7 短信验证码DDoS攻击
应用程序在向手机发送短信验证码时,需在服务器端设置并判断时间间隔,防止攻击者通过重复提交请求对目标用户的手机造成短信DDoS攻击。
代码示例:
public String createSignCode() throws HandlerException {
signCode = CommonUtil.createRandomCode(6);
return signCode
}
//代码片段功能为生成验证码,可见其中未对发送验证码的频率做限制,导致攻击者可以重复请求发送验证码的URL对目标用户的手机造成短信DDoS