系统安全架构方面的探讨
一、基础设施安全
这个不用多说,服务器、操作系统都要用正规的高质量的,安装杀毒软件防火墙,使用攻击检测系统。
二、应用系统安全
开发程序的时候,应当事先知道并在代码层面处理大部分常见的安全问题。
1.sql注入
mybatis就使用#比使用$能规避掉很多sql注入攻击。
2.csrf(跨站请求伪造)攻击
大致三种方法,①在filter中验证HTTP Referer字段,②在请求地址中添加token并验证,③在HTTP头中自定义属性并验证,一般我是通过toekn验证,
具体参见https://www.ibm.com/developerworks/cn/web/1102_niugang_csrf/
3.xss(跨站脚本)攻击
总体的防御思路是对输入(和URL参数)进行过滤,对输出进行编码。
java代码示例
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper { HttpServletRequest orgRequest = null; public XssHttpServletRequestWrapper(HttpServletRequest request) { super(request); orgRequest = request; } /** * 覆盖getParameter方法,将参数名和参数值都做xss过滤。<br/> * 如果需要获得原始的值,则通过super.getParameterValues(name)来获取<br/> * getParameterNames,getParameterValues和getParameterMap也可能需要覆盖 */ @Override public String getParameter(String name) { String value = super.getParameter(xssEncode(name)); if (value != null) { value = xssEncode(value); } return value; } /** * 覆盖getHeader方法,将参数名和参数值都做xss过滤。<br/> * 如果需要获得原始的值,则通过super.getHeaders(name)来获取<br/> * getHeaderNames 也可能需要覆盖 */ @Override public String getHeader(String name) { String value = super.getHeader(xssEncode(name)); if (value != null) { value = xssEncode(value); } return value; } /** * 将容易引起xss漏洞的半角字符直接替换成全角字符 * * @param s * @return */ private static String xssEncode(String s) { if (s == null || s.isEmpty()) { return s; } StringBuilder sb = new StringBuilder(s.length() + 16); for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); switch (c) { case '>': sb.append('>');// 全角大于号 break; case '<': sb.append('<');// 全角小于号 break; case '\'': sb.append('‘');// 全角单引号 break; case '\"': sb.append('“');// 全角双引号 break; case '&': sb.append('&');// 全角 break; case '\\': sb.append('\');// 全角斜线 break; case '#': sb.append('#');// 全角井号 break; case '%': // < 字符的 URL 编码形式表示的 ASCII 字符(十六进制格式) 是: %3c processUrlEncoder(sb, s, i); break; default: sb.append(c); break; } } return sb.toString(); } public static void processUrlEncoder(StringBuilder sb, String s, int index){ if(s.length() >= index + 2){ if(s.charAt(index+1) == '3' && (s.charAt(index+2) == 'c' || s.charAt(index+2) == 'C')){ // %3c, %3C sb.append('<'); return; } if(s.charAt(index+1) == '6' && s.charAt(index+2) == '0'){ // %3c (0x3c=60) sb.append('<'); return; } if(s.charAt(index+1) == '3' && (s.charAt(index+2) == 'e' || s.charAt(index+2) == 'E')){ // %3e, %3E sb.append('>'); return; } if(s.charAt(index+1) == '6' && s.charAt(index+2) == '2'){ // %3e (0x3e=62) sb.append('>'); return; } } sb.append(s.charAt(index)); } /** * 获取最原始的request * * @return */ public HttpServletRequest getOrgRequest() { return orgRequest; } /** * 获取最原始的request的静态方法 * * @return */ public static HttpServletRequest getOrgRequest(HttpServletRequest req) { if (req instanceof XssHttpServletRequestWrapper) { return ((XssHttpServletRequestWrapper) req).getOrgRequest(); } return req; } }
具体参见https://www.cnblogs.com/digdeep/p/4695348.html
4.文件上传漏洞防御
大致思路:①文件上传的目录设置为不可执行 ②判断文件类型 ③使用随机数改写文件名和文件路径 ④单独设置文件服务器的域名 ⑥在客户端和服务器端对用户上传的文件名和文件路径等项目进行双重验证 ⑦服务器端添加白名单过滤 ⑧对%00截断符进行检测 ⑨对HTTP包头的content-type也和上传文件的大小进行检查
具体参见http://blog.csdn.net/u014609111/article/details/52701827
5.路径遍历攻击防御
最有效的办法就是权限控制,谨慎处理传向文件系统API的参数,净化数据:对用户传过来的文件名参数进行硬编码或统一编码,对文件类型进行白名单控制,对包含恶意字符或者空字符的参数进行拒绝。
三、数据保密安全
1.存储安全(存在在可靠的设备,实时,定时备份)
2.保存安全(重要的信息加密保存,选择合适的人员复杂保存和检测等)
3.传输安全(防止数据窃取和数据篡改)
常用的加解密算法(单项散列加密[MD5,SHA],对称加密[DES,3DES,RC]),非对称加密[RSA]等。
目前大多数网站和app的接口都是采用http协议,但是http协议很容易就通过抓包工具监听到内容,甚至可以篡改内容,为了保证数据不被别人看到和修改,可以通过以下几个方面避免。
①重要数据进行加密传输
常见的是传密码的时候对密码进行MD5(本质是一种散列算法,和AES等加密算法不一样,因为不是加密,所以不可以解密,网上的所谓MD5解密,其实是在海量数据里的一种反推)加密。
②非重要数据进行签名
签名的目的是为了防止篡改,比如http://www.xxx.com/getnews?id=1,获取id为1的新闻,如果不签名那么通过id=2,就可以获取2的内容等等。怎样签名呢?通常使用sign,比如原链接请求的时候加一个sign参数,sign=md5(id=1),服务器接受到请求,验证sign是否等于md5(id=1),如果等于说明正常请求。这会有个弊端,假如规则被发现,那么就会被伪造,所以适当复杂一些,还是能够提高安全性的。
我自己的一个项目是用SHA 256(也是一种散列算法)加密做sign的,具体的规则是调接口的时候,把每个参数加上一个key(一个任意字符串标记,比如网站的域名)拼接成一个整个字符串,然后用SHA 256加密,把加密好的字符串也一起传到后台,后台再拿每个参数加上key进行SHA 256加密,拿加密好的字符串与传过来的加密过的字符串比对。
③用token验证登陆态
http是无状态的,也就是服务器没法自己判断两个请求是否有联系,那么登录之后,以后的接口怎么判定是否登录呢,简单的做法,在数据库中存一个token字段(名字随意),当用户调用登陆接口成功的时候,就将该字段设一个值,(比如aes(过期时间)),同时返回给前端,以后每次前端请求带上该值,服务器首先校验是否过期,其次校验是否正确,不通过就让其登陆。(redis 做这个很方便哦,key有过期时间)
4.防重放机制
防止别有用心的人获取到请求地址,然后原封不动的连续重复请求,导致系统阻塞和数据库负载,需要有防重放机制,http://www.cnblogs.com/yjf512/p/6590890.html
阅读文章
基于http协议的api接口对于客户端的身份认证方式以及安全措施 http://www.cnblogs.com/gmou/p/4458754.html