验证码安全编码规范
String userName = request.getParameter("adminname");
String userPwd = request.getParameter("adminpwd");
//从session中取得验证码
String validateCode=(String)request.getSession().getAttribute("rand");
//获取用户输入的验证码
String userInput=request.getParameter("validateCode");
if(userName__null||userPwd__null)
return;
if(validateCode!=null) {
if(!validateCode.equalsIgnoreCase(userInput)) {
out.print("<script>alert('验证错误! ');window.location='AdminLogin.jsp'</script>");
//移除使用过的验证码
request.getSession().removeAttribute("rand");
return;
} else {
request.setAttribute("message", "验证正确");
}
boolean loginValid=dao.LoginStatus(userName, userPwd);
if(loginValid) {
request.getSession().invalidate();
request.getSession().setAttribute("AdminName", userName);
out.print("<script>alert('登录成功,跳转到首页');window.location='AdminIndex.jsp'</script>");
} else {
out.print("<script>alert('用户名或密码错误!');window.location='AdminLogin.jsp'</script>");
}
//移除使用过的验证码
request.getSession().removeAttribute("rand");
}
public boolean checkUser(String username,String password) {
try {
//使用预编译的方式防止产生注入
pstmt=ct.prepareStatement("select * from userTable where username=? and password=?");
pstmt.setString(1, username);
//密码加密
pstmt.setString(2, Entrypt. string2MD5(password,salt));
ResultSet rs=pstmt.executeQuery();
User user=new User();
while(rs.next()) {
user.setId(rs.getInt(1));
user.setUsername(rs.getString(2));
user.setPassword(rs.getString(3));
//更新session数据
HttpSession session=dhUtil.changeSessionIdentifier(request);
session. .setAttribute("username", username);
return user;
}
return null;
} catch(Exception e) {
return null;
}
}
public void logout() {
ESAPI.httpUtilities().killCookie( ESAPI.currentRequest(),ESAPI.currentResponse(),HTTPUtilities.REMEMBER_TOKEN_COOKIE_NAME );
HttpSession session = ESAPI.currentRequest().getSession(false);
if (session != null) {
removeSession(session);
session.invalidate();
}
ESAPI.httpUtilities().killCookie(ESAPI.currentRequest(),ESAPI.currentResponse(),"JSESSIONID");
loggedIn = false;
logger.info(Logger.SECURITY_SUCCESS, "Logout successful" );
ESAPI.authenticator().setCurrentUser(User.ANONYMOUS);
ESAPI.httpUtilities().sendRedirect(“登录页面”);
}
Java:
response.sendRedirect(request.getParameter("url"))
PHP:
$redirect_url = $_GET['url'];
header("Location: " . $redirect_url)
.NET:
string redirect_url = request.QueryString["url"];
Response.Redirect(redirect_url);
Django:
redirect_url = request.GET.get("url")
HttpResponseRedirect(redirect_url)
Flask:
redirect_url = request.form['url']
redirect(redirect_url)
Rails:
redirect_to params[:url]
写代码时没有考虑过任意URL跳转漏洞,或者根本不知道/不认为这是个漏洞;
写代码时考虑不周,用取子串、取后缀等方法简单判断,代码逻辑可被绕过;
对传入参数做一些奇葩的操作(域名剪切/拼接/重组)和判断,适得其反,反被绕过;
原始语言自带的解析URL、判断域名的函数库出现逻辑漏洞或者意外特性,可被绕过;
原始语言、服务器/容器特性、浏览器等对标准URL协议解析处理等差异性导致被绕过;
—
<form action="http://spdb.com/modify.jsp" method="POST">
<input name="email">
<input name="tel">
<input name="realname">
<input name="userid">
<input type="submit">
</form>
//因为表单中没有token,以上代码中存在csrf漏洞
protected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException
{
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String contentType = request.getContentType();
int ind = contentType.indexOf("boundary=");
String boundary = contentType.substring(ind+9);
String pLine = new String();
String uploadLocation = new String(UPLOAD_DIRECTORY_STRING);
//判断contentType是否是multipart/form-data
if (contentType != null && contentType.indexOf("multipart/form-data") != -1)
{
//从HttpHeader中提取文件名
BufferedReader br = new BufferedReader(new InputStreamReader(request.getInputStream()));
...
pLine = br.readLine();
String filename = pLine.substring(pLine.lastIndexOf("\\"),pLine.lastIndexOf("\""));
...
//把文件输出到上传目录
try {
BufferedWriter bw = new BufferedWriter(new FileWriter(uploadLocation+filename, true));
for (String line; (line=br.readLine())!=null; ) {
if (line.indexOf(boundary) __ -1) {
bw.write(line);
bw.newLine();
bw.flush();
}
} //循环结束
bw.close();
}
catch (IOException ex) {...}
//输出成功加载并返回的HTML页面
}
//输出成功加载并返回的HTML页面
else
{...}
}
5.文件下载
注意点
protected void doPost(HttpServletRequest request,HttpServletResponse response)throws ServletException, IOException
{
try {
byte data[] = new byte[1];
//取得用户提交的图片文件名,没有检测是否为图片,也没有检测是否包含../../目录跳转的字符
String imgName = request.getParameter("imgName");
String imgKey = MD5Encrypt.MD5(imgName); //本地
if (imageCache.containsKey(imgKey)) {
data = (byte[]) imageCache.get(imgKey);
} else {
String imagePath = Consts.IMG_LOCAL_PAHT + imgName;
//没有对该参数进行严格的验证和过滤,就拼接成完整的图片路径
InputStream inputStream = null;
File imageFile = new File(imagePath);
logger.debug(imagePath + " " + imageFile.exists());
if (imageFile.exists() && imageFile.isFile()) {
inputStream = new FileInputStream(imagePath);
int i = inputStream.available();
data = new byte[i];
inputStream.read(data);
inputStream.close();
imageCache.put(imgKey, data);
} else {
……
}
}
//将文件内容输出到客户端
response.setContentType("image/*");
OutputStream outputStream = response.getOutputStream();
outputStream.write(data);
outputStream.close();
}
}
6.重定向和转发
注意点
public class RedirectServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException
{
String query = request.getQueryString();
if (query.contains("url")) {
String url = request.getParameter("url");
response.sendRedirect(url);
}
}
}
//服务端从客户端接收参数url,直接指定其为重定向地址
1.越权漏洞 获取数据时权限未验证,可以控制查询数据
1.逻辑漏洞
交易重放
密码重置
找回密码
修改密码
短信验证码发送间隔控制
1.iBatis(MyBatis)框架
代码示例
代码示例:mapper文件
select * from messages where username=#{username}
//这种写法不会产生SQL注入
select * from user where username like '%$username$%'
//这种like写法会产生SQL注入
//在ibatis中,“#”会对传入的变量进行转义,“$”则是直接拼接
hibernate
代码示例
代码示例:java代码:
Sring hql=”from User where username=’”+name+”’ and password=’”+password+”’;
User u = session.find(hql);
//在hibernate中使用hql时,要尽量避免使用拼接方式
除了$_GET,$_POST,$_Cookie的提交之外,还来源于$_SERVER,$_ENV, $_SESSION 等register_globals = on [未初始化的变量] 当On的时候,传递过来的值会被直接的注册为全局变量直接使用,而Off的时候,我们需要到特定的数组里去得到它,PHP » 4.20 默认为off
如:$$使用不当、遍历初始化变量、 extract() 、parse_str()等 文件包含包含漏洞:require、include、require_once、include_once
存储于数据库、文件[如配置、缓存文件等
eval()、assert()、preg_replace()、create_function()
exec()、passthru()、proc_open()、shell_exec()、system()、popen()
file_get_contents、file_put_contents、fopen、readfile
select from、mysql_connect、mysql_query、mysql_fetch_row
print、print_r、echo、print、sprintf、die、Var_dump、var_export