1. 设计阶段的安全考虑
1.1. 清晰定义安全用例。用例设计要考虑所有的边界情况,覆盖所有可能的异常路径。(把异常路径写进用例中)
1.2. 统一的认证入口,或称单点登入。入口可以提供直接的认证方式(Form,Client Certificate)或者间接的(联邦)认证方式。所有的应用和服务都应当通过认证。
1.3. 单点注销。如果用户从入口点注销,那BSS需要引导用户把所有已经打开的应用都注销掉。
1.4. 服务器间调用的认证:
- 服务器间可以共享一对称密钥,调用方把用户ID用这个密钥加密后作为一个token放到HTTP请求头里,服务方解密即可。如果不能解密说明不是信任的服务器。
- 也可以用PKI密钥来完成。调用方使用服务方的公钥对用户ID做加密,用自己的私钥做签名,然后放到HTTP请求头里。
- 也可以建立一个STS服务。每一个调用方先到STS请求一个token,然后用这个token去访问服务方。
1.5. 信息保护
- 密码、秘密和token在存储的时候需要加密。
- 所有的传输都应该基于SSL。
- 富客户端、移动设备都应当存储共享密钥。
1.6. API访问
- OAuth,外部应用可使用OAuth。
- Basic Auth。
2. 代码安全标准
2.1. XSS防护
XSS发生在用户的输入中,用户有可能在输入中带有一些java script,如果程序逻辑不对用户输入做任何过滤就返回到browser,那这些java script就会被执行,从而导致一些问题。
解决的策略就是不要把用户的输入原封不动得响应回去,而是对用户输入的内容做escape处理,如下面的代码:
private static String escapeUnwiseCharacters(String uri) {
// According to the RFC 2396 under the section:
// 2.4.3. Excluded US-ASCII Characters,
// spaces are disallowed in addition to the following unwise
// characters:
// "{" | "}" | "|" | "\" | "^" | "[" | "]" | "`" | "<" | ">"
// We will use this method to escape the space and unwise characters in
// the a URI since they are found to be used in practice, eventhough unwise
// and have no special meaning in the URI syntax.
if (uri != null) {
StringBuffer sb = new StringBuffer(uri.length() + uri.length()/4);
for(int i=0; i < uri.length(); i++) {
char pos = uri.charAt(i);
switch (pos) {
case '|': sb.append("%7C"); break;
case ' ': sb.append("%20"); break;
case '\\': sb.append("%5C"); break;
case '^': sb.append("%5E"); break;
case '{': sb.append("%7B"); break;
case '}': sb.append("%7D"); break;
case '[': sb.append("%5B"); break;
case ']': sb.append("%5D"); break;
case '`': sb.append("%60"); break;
case '<': sb.append("%3C"); break;
case '>': sb.append("%3E"); break;
default: sb.append(pos); break;
}
}
return sb.toString();
} else {
return null;
}
}
2.2. CSRF防护
CSRF主要发生在一些关键性的REST API或敏感信息的输入请求上。现代浏览器都是多tab页的,tab页之间是可以共享cookie的。假设用户打开并登录某网银页面,同时在另外一个tab页上打开另外一个网站。这个网站上可能会有某个image tag,它实际指向的URL被写成了网银某REST API的请求。那么这个请求就会以合法用户的身份被网银接受。
解决的策略很简单,一般用双提交策略。在cookie里面放一个随机数,同时在请求里也放这个随机数即可。服务器端对这两个值做一下比对即可。
或者server生成一个随机数的密文,送给客户端。当请求过来的时候,看请求头里带过来的密文是否能被解开即可。
2.3. 慎重处理用户提供的File/URL
要慎重处理用户提供的URL。如果需要渲染用户提供的URL,只允许HTTP协议开头的URL。
不要让用户用相对路径访问到根目录,如../../../../../../../etc/passwd.
不要从服务器端访问用户提供的URL
2.4. SQL注入
不要用字符串拼SQL,使用参数化的查询API。
2.5. 用户上传文件
所有用户上传的文件要经过防毒软件过滤。
不要让用户直接下载其他用户上传的文件,因为他可能上传一个含有恶意代码的HTML文件,这样当用户下载这个HTML文件的时候,浏览器很可能直接就去渲染这个HTML文件了。
如果用户想下载HTML文件,Content-Type:application/x-download,Content-Disposition:attachment。
2.6. URL参数
不用把用户信息(比如用户名,或者EMail)作为URL的参数出现。在URL参数中一般使用ID.