返回 登录
0

浅谈JSP开发的安全问题之SQL防注入

阅读3275

作者:0nise
时间:2016年8月11日 14:22:55
社区:i春秋
前言
不管是用什么语言编写WEB应用程序,他们都或多或少有一些地方存在漏洞。如果你想知道漏洞的运行原理,和防御方案,那么请看完本篇文章。
目录
第一节 注入攻击原理及防御
1.1、什么是SQL注入
1.2、SQL注入演练
1.3、如何防御SQL注入
正文
第一节 注入攻击原理及防御
1.1、什么是SQL注入
所谓SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。
1.2、SQL注入演练
Servlet普及
1.Servlet简介
  Servlet是sun公司提供的一门用于开发动态web资源的技术。
   Sun公司在其API中提供了一个servlet接口,用户若想用发一个动态web资源(即开发一个Java程序向浏览器输出数据),需要完成以下2个步骤:
   1、编写一个Java类,实现servlet接口。
   2、把开发好的Java类部署到web服务器中。
   按照一种约定俗成的称呼习惯,通常我们也把实现了servlet接口的java程序,称之为Servlet
2.Servlet的运行过程
Servlet程序是由WEB服务器调用,web服务器收到客户端的Servlet访问请求后:
   ①Web服务器首先检查是否已经装载并创建了该Servlet的实例对象。如果是,则直接执行第④步,否则,执行第②步。
   ②装载并创建该Servlet的一个实例对象。
   ③调用Servlet实例对象的init()方法。
   ④创建一个用于封装HTTP请求消息的HttpServletRequest对象和一个代表HTTP响应消息的HttpServletResponse对象,然后调用Servlet的service()方法并将请求和响应对象作为参数传递进去。
   ⑤WEB应用程序被停止或重新启动之前,Servlet引擎将卸载Servlet,并在卸载之前调用Servlet的destroy()方法。

3.Servlet的常用方法
doPost() 方法
当一个客户通过 HTML 表单发出一个 HTTP POST 请求时,doPost() 方法被调用。与 POST 请求相关的参数作为一个单独的 HTTP 请求从浏览器发送到服务器。当需要修改服务器端的数据时,应该使用 doPost() 方法。
doGet() 方法
当一个客户通过 HTML 表单发出一个 HTTP GET 请求或直接请求一个 URL 时,doGet() 方法被调用。与 GET 请求相关的参数添加到 URL 的后面,并与这个请求一起发送。当不会修改服务器端的数据时,应该使用 doGet() 方法。
我们来看一段JSP代码中的【登陆验证】
login.jsp核心代码
[Java] 纯文本查看 复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15

用户名:
密码:

UserServlet核心代码
[Java] 纯文本查看 复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
/**
* doGet()
*/
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

response.setContentType(“text/html;charset=UTF-8”);
request.setCharacterEncoding(“UTF-8”);
PrintWriter out = response.getWriter();
String opr = request.getParameter(“opr”);
String name = request.getParameter(“name”);
String pwd = request.getParameter(“pwd”);
BaseDao baseDao = new BaseDao();
admin user = new admin();
user.setName(name);
user.setPass(pwd);
if(opr.equals(“login”)){
String sql = “SELECT id,name,pass FROM [admin] WHERE name = ‘”+user.getName()+”’ AND pass = ‘”+user.getPass()+”’”;
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
admin admin = null;
try {
conn = baseDao.getConn();
stmt = conn.createStatement();
rs = stmt.executeQuery(sql);
while(rs.next()){
admin = new admin();
admin.setId(rs.getInt(“id”));
admin.setName(rs.getString(“name”));
admin.setPass(rs.getString(“pass”));
}
} catch (Exception e) {
e.printStackTrace();
}
if(admin != null){
out.print(“登陆成功,欢迎”+admin.getName());
}
}
out.flush();
out.close();
}
/**
* doPost()
*/
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}

我们来构造登陆代码
用户名:
[Java] 纯文本查看 复制代码
?
1
’ or 1=1 –

密 码:
[Java] 纯文本查看 复制代码
?
1
123

然后通过断点捕获的SQL执行语句

[SQL] 纯文本查看 复制代码
?
1
SELECT id,name,pass FROM [admin] WHERE name = ” or 1=1 –’ AND pass = ‘123’

相关的代码代码剖析
传送门:http://bbs.ichunqiu.com/thread-7636-1-1.html
1.3、SQL注入防御方案
预编译语句集,通过setting方法对参数进行赋值
UserServlet核心代码
[Java] 纯文本查看 复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
/**
* doGet()
*/
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

response.setContentType(“text/html;charset=UTF-8”);
request.setCharacterEncoding(“UTF-8”);
PrintWriter out = response.getWriter();
String opr = request.getParameter(“opr”);
String name = request.getParameter(“name”);
String pwd = request.getParameter(“pwd”);
BaseDao baseDao = new BaseDao();
admin user = new admin();
user.setName(name);
user.setPass(pwd);
if(opr.equals(“login”)){
String sql = “SELECT id,name,pass FROM [admin] WHERE name = ? AND pass = ?”;
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
admin admin = null;
try {
conn = baseDao.getConn();
stmt = conn.prepareStatement(sql);
stmt.setString(1, user.getName());
stmt.setString(2, user.getPass());
rs = stmt.executeQuery();
while(rs.next()){
admin = new admin();
admin.setId(rs.getInt(“id”));
admin.setName(rs.getString(“name”));
admin.setPass(rs.getString(“pass”));
}
} catch (Exception e) {
e.printStackTrace();
}
if(admin != null){
out.print(“登陆成功,欢迎”+admin.getName());
}else{
out.print(“登陆失败!”);
}
}
out.flush();
out.close();
} /**
* doPost()
*/
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}

构造登陆代码

用户名:

[Java] 纯文本查看 复制代码
?
1
’ or 1=1 –

密  码:

[Java] 纯文本查看 复制代码
?
1
123

然后通过断点捕获的SQL执行语句

[SQL] 纯文本查看 复制代码
?
1
SELECT id,name,pass FROM [admin] WHERE name = ? AND pass = ?

我们可以发现我们的SQL语句跟我们原来构造没有发生任何变化,从而避免了SQL注入的发生!
如果你觉得SQL注入不重要那么请看这里
传送门:http://bbs.ichunqiu.com/thread-8005-1-1.html
结束语
个人感觉在开发中,应该放在第一位的就是安全。
系列文章预告及导航
浅谈JSP开发的安全问题之XSS攻击(更新中)
第二节 XSS攻击原理以及防御
2.1、什么是XSS漏洞
2.2、如何防御XSS
浅谈JSP开发的安全问题之未授权访问(更新中)
第三节 未授权访问
3.1、什么是未授权访问
3.2、如何防御未授权访问
浅谈JSP开发的安全问题之恶意文件(更新中)
第四节 恶意文件上传
4.1、什么是文件上传
4.2、如何防御恶意文件上传

本文转载自【http://bbs.ichunqiu.com/thread-9958-1-1.html?from=mysky

评论