web安全測試&滲透測試之sql注入~~


滲透測試概念:

   詳見百度百科

http://baike.baidu.com/link?url=T3avJhH3_MunEIk9fPzEX5hcSv2IqQlhAfokBzAG4M1CztQrSbwsRkSerdBe17H6tTF5IleOCc7R3ThIBYNO-q

 

前言:

安全測試范圍極廣,開門見山,樓主對這行了解的也不是太深,也是在學習探索階段,此文,也是對自己學習的總結與記錄和簡單的分享;這里沒有具體工具的使用方法,更多的是原理細節的了解和解決方案的探討。

 

code部分:

html+jsp+mysql,實現登錄與新增數據功能。

html

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>web安全測試之sql注入</title>
</head>
<body bgcolor="#ffffff">
<form action="chkLogin.jsp" method="POST">
  <input type="text" name="user" /><br />
  <input type="password" name="pass" /><br />
  <input type="Submit" value="登錄" />
</form>
<form action="insert.jsp" method="POST">
  <input type="text" name="user" /><br />
  <input type="text" name="pwd" /><br />
  <input type="Submit" value="新增" />
</form>
</body>
</html>
View Code

jsp1

<%@ page contentType="text/html; charset=utf-8" %>
<%@ page import="java.sql.*" %>
<html>
<head>
<title>chkLogin.jsp</title>
</head>
<body bgcolor="#ffffff">
<%
  String user = request.getParameter("user");
  String pass = request.getParameter("pass");

  Connection con = null;
  PreparedStatement ps = null;
  ResultSet rs = null;
  String sql =null;
  try
  {
    Class.forName("com.mysql.jdbc.Driver");
    con = java.sql.DriverManager.getConnection("jdbc:mysql://192.168.0.157/webTest?useUnicode=true&characterEncoding=utf-8","root","123456");
    sql= "SELECT * FROM user WHERE name='"+user+"' AND pwd ='"+pass+"'";
    ps = con.prepareStatement(sql);
//    ps = con.prepareStatement("SELECT * FROM user WHERE name=? AND pwd =?");
//    ps.setString(1, user);
//    ps.setString(2, pass);
    rs = ps.executeQuery();
    if ( rs.next())
    {

      out.println("登錄成功!");
      out.println("sql:"+sql);
    }
    else
    {
      out.println("登錄失敗!");
      out.println("sql:"+sql);
    }
  }catch(Exception ex)
  { 
     out.println("登錄異常!");
     out.println("sql:"+sql);  
     out.println("Exception:"+ex);
  }finally{
    if ( null != rs)
    {
      rs.close();
      rs = null;
    }
    if ( null != ps)
    {
      ps.close();
      ps = null;
    }
    if ( null != con){
      con.close();
      con = null;
    }
  }
%>
</body>
</html>
View Code

jsp2

<%@ page contentType="text/html; charset=utf-8" %>
<%@ page import="java.sql.*" %>
<html>
<head>
<title>chkLogin.jsp</title>
</head>
<body bgcolor="#ffffff">
<%
  String user = request.getParameter("user");
  String pass = request.getParameter("pwd");

  Connection con = null;
  PreparedStatement ps = null;
  ResultSet rs = null;
  String sql =null;
  int r = 0;
  try
  {
    Class.forName("com.mysql.jdbc.Driver");
    con = java.sql.DriverManager.getConnection("jdbc:mysql://192.168.0.157/webTest?useUnicode=true&characterEncoding=utf-8","root","123456");
    sql= "insert into user(name,pwd) values ('"+user+"','"+pass+"')";
    ps = con.prepareStatement(sql);
//    ps = con.prepareStatement("SELECT * FROM user WHERE name=? AND pwd =?");
//    ps.setString(1, user);
//    ps.setString(2, pass);
    r = ps.executeUpdate();
    
    if (r>0)
    {

      out.println("添加成功!");
      out.println("sql:"+sql);
    }
    else
    {
      out.println("添加失敗!");
      out.println("sql:"+sql);
    }
  }catch(Exception ex)
  { 
     out.println("添加異常!");
     out.println("sql:"+sql);  
     out.println("Exception:"+ex);
  }finally{
    if ( null != rs)
    {
      rs.close();
      rs = null;
    }
    if ( null != ps)
    {
      ps.close();
      ps = null;
    }
    if ( null != con){
      con.close();
      con = null;
    }
  }
%>
</body>
</html>
View Code

 

登錄原理簡介:

html->jsp->db

html頁面輸入兩個參數user、pass,按‘登錄’按鈕,調用chkLogin.jsp;chkLogin.jsp接收html傳入兩個參數,去數據庫user表里面查詢,返回不為null,則登錄成功,否則登錄失敗,異常則登錄異常。查詢使用的方法是executeQuery,sql組裝使用的+參數拼接。

 

正常場景:

數據庫用戶數據

頁面登錄(密碼錯誤)

頁面登錄正常

 

到這里為止,我們的實驗的環境有了,現在可以大展手腳了~~開始~

sql注入實例1(不知道用戶密碼密碼情況下,登錄):

界面信息輸入值

user:test

pwd: ' or 1=1; -- 

 

效果

 

sql注入實例2(不知道用戶名與密碼情況下,登錄):

界面信息輸入值:

user:' or 1=1 ; --

pwd:

效果:

 

 

上面兩個實例攻防升級案例:

初級方案:界面前端控制--界面參數做過濾與限制;比如' -- ;字符,or字符等;

應對方案:通過fiddler等http協議抓包工具,用戶名與密碼可以自由編輯,注意瀏覽器做了url編碼,直接請求繞過前端字符串控制。

 

 

實例的升級方案:

中級方案:前端控制+邏輯業務控制,邏輯業務控制舍棄使用+拼接方方式,采取獲取參數方式實現:

ps = con.prepareStatement("SELECT * FROM user WHERE name=? AND pwd =?");
ps.setString(1, user);
ps.setString(2, pass);

應對方案:

界面字符串輸入參數注入與http協議接口方式參數注入失效。

嘗試方案(未實踐):

對參數進行各種編碼轉義,這個環節的內容比較多,樓主水平有限,這塊有興趣的歡迎補充。

 

以上,就是一個簡單的實例,從以上列子中,也沒見到多大的危險性啊,只是進入系統而已~~也沒見到能產生多大的危險性與數據泄露的重大風險漏洞啊啊~~好的,大菜開始上場~~

新增數據功能原理:

參考登錄~

新增功能正常使用:

 

sql注入實例3(任意添加數據):

界面輸入數據

test','test'),('1','2'); -- 

效果:

 

好戲從這里開始~~

第一步,獲取當前數據庫版本,SELECT version()的使用~

sql注入實例4:

界面輸入信息

test',(SELECT version())) -- 

效果:

 

第二步,獲取數據庫數據庫對象,information_schema.TABLES使用~

sql注入實例5:

界面輸入參數:

test',(select table_schema from information_schema.TABLES group by table_schema limit 1)); -- 

效果:

dblist

界面:

數據:

后面的過程就是周而復始,你懂的~直到獲取所有db

第三步,獲取db庫下面的表對象與表結構

方法類似,對 information_schema.TABLES熟悉

第四步,獲取db用戶名信息

哈哈,方式類似,對information_schema.user熟悉

第五步,重置用戶密碼

哈哈,方式類似,對information_schema熟悉

第六步,獲取ip,這個很多方式

 

上面都得到了,差不多可以宣告GG了~~

 

解決方案&探討:

從兩個維度來分析,第一個應用層角度,從前端到業務層再到db層。

第二個維度,從軟件七層架構角度來,應用層->傳輸層->網絡層->數據鏈路層->物理層.

 

具體如下

1.前端對參數嚴格控制;

2.業務層不要使用拼接字符串實現方式;

3.業務功能請求,增加token字段控制,每次post請求對koken進行有效驗證;

4.傳輸協議,涉及到數據接口參數安全,采取https協議傳輸;

5.數據庫,采取最小原子控制,對用戶,用戶權限進行嚴格的權限控制,能做數據讀取與數據插入的業務能單獨分別使用不同用戶盡量區分;

6.應用層訪問db,對數據庫配置相關信息,特別是pwd字段進行特定算法加密;

7.數據庫與應用程序部署在內網環境,與外網進行隔離;

8.系統方面,歡迎運維童鞋補充;

9.其它維度歡迎補充與討論。

 

現碼的,下班~周末快樂~

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM