前言:
以前編寫了一個網頁闖關遊戲(相似Riddle Game), 除了但願你們可以體驗一下個人遊戲外. 也願意分享編寫這個網頁遊戲過程當中, 學到的一些知識.
web開發初學者每每會忽視一些常見的漏洞, 好比SQL注入攻擊, XSS攻擊. 本文將簡述SQL注入攻擊的原理, 並分享下關卡設計, 其在打開潘多拉魔盒的狀況下, 又能很好地限制危害.html
效果展現:
先打下廣告: 網頁闖關遊戲入口(請狠狠地點擊我, ^_^).
本文的想法實施於第十一關--健忘的教授.
很直接的呈現一個登錄對話框, 考驗玩家可否藉助很是規的方式來繞開登錄驗證.java
SQL注入攻擊:
雖然SQL注入攻擊已經是老生常談, 不過仍是得嘮叨幾句"科普"一下, ^_^.
應用程序再獲取到用戶提交的數據後, 有些會進行SQL語句的拼接並執行. 假若用戶提交的數據中包含SQL執行命令, 同時程序並沒有對數據進行過濾和安全驗證. 這樣就有可能繞過驗證並獲取數據, 甚至注入惡意代碼, 致使數據被篡改, 丟失.
• 以用戶登陸爲例
服務的用戶數據模型以下:mysql
table tb_user ( username varchar(32), password varchar(32) );
服務的登錄驗證SQL以下:web
SELECT * FROM tb_user WHERE username = '?' AND password = '?';
登錄的輸入框入圖所示:
其對應的form表單爲:sql
<form method="post"> 用戶名: <input name="username" /> 密碼: <input name="password" type="password"/> </form>
hacker只要在form表單中, 巧妙設計字段內容, 注入sql執行命令, 以繞過數據驗證.
好比username字段, 填寫爲: ' or 1 = 1 #.
這樣服務器端, 最終拼接的SQL爲:安全
SELECT * FROM tb_user WHERE username = '' or 1 = 1 #' AND password= '?'
因爲字符'#'在SQL規範中, 表示註釋, '#'字符後直到行尾的全部字符都將被忽略掉.
所以最終的SQL等價於以下:服務器
SELECT * FROM tb_user WHERE username = '' or 1 = 1
用戶數據將被返回, 若是嘗試登陸的是管理員後臺, 那hacker將輕鬆獲取到管理員的權限, 這很是的可怕.
魔高一丈道高一尺, 既然知道SQL注入的攻擊原理是什麼? 那麼防範措施就有針對性了, 千萬不要相信用戶提交的數據, 作好過濾和驗證.微信
關卡設計:
本關就是來考察玩家對SQL注入的認知功底. 所以模擬構建了一個登錄窗口, 接受開放式的答案.
如何對答案進行驗證呢? 1). 模擬SQL的執行解析. 2). 直接跑真實的SQL.
對於方案一, 工做量大, 多個SQL命令須要支持, 有可能覆蓋不全全部的解, 有點得不償失.
對於方案二, 容易實現, 可是給系統帶來了潛在風險, 好比注入drop tables等危險的命令.
權衡比較, 仍是採用第二種方案, 至於風險控制亦可控.
服務程序是採用Java來編寫的, 若要放開SQL注入漏洞限定, 那就不能使用mybatis/hibernate這些ORM框架, 由於這些框架已經幫咱們作了escape數據的工做.
讓咱們回到石器時代, 直接裸用jdbc來實現, 代碼以下:mybatis
/** * * 構造經典的SQL注入攻擊 * @param username 用戶輸入的用戶名 * @param password 用戶輸入的密碼 * @return */ public boolean verifySQLInject(String username, String password) { Connection connection = null; try { // *) 動態載入Mysql Driver驅動類 Class.forName("com.mysql.jdbc.Driver"); // *) 獲取 DB Connection connection = DriverManager.getConnection(dbUrl, dbUsername, dbPassword); Statement stmt = connection.createStatement(); String sql = String.format( "SELECT * " + "FROM tb_virtual_user " + "WHERE username = '%s' AND password = '%s'", username, password ); ResultSet rs = stmt.executeQuery(sql); if ( rs.next() ) { stmt.close(); // *) 登錄成功 return true; } } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } finally { if ( connection != null ) { try { connection.close(); } catch (SQLException e) { // e.printStackTrace(); } } } return false; }
注: 該代碼確切地執行了用戶登陸的SQL語句, 常規登陸和非法sql注入構造都將返回失敗.
同時正如前文所提到的, 爲了驗證SQL注入攻擊, 從而放棄數據驗證和過濾. 萬一有人不是用於解題, 而是專門搞破壞怎麼辦? 猶如本身給本身埋了個炸彈, 你永遠不知道它何時爆炸.
事實上, 這是多慮的. 咱們能夠建立兩個mysql帳號, 一個專門用於sql注入驗證(只授予select權限), 而剩下則用於其餘的業務數據. 這樣就輕鬆作到隔離, 且十分安全.框架
GRANT USAGE ON *.* TO 'game1001'@'localhost' IDENTIFIED BY PASSWORD '*25A2CD7698FEED80089150F089755D752423A821'; GRANT SELECT ON `db_gameweb`.`tb_virtual_user` TO 'game1001'@'localhost';
好比建立帳號game1001, 它只被授予對tb_virtual_user表的只讀權限.
這樣服務就能容許sql注入存在, 但這些sql注入不具攻擊性.
後記:
其實對該題, 我仍是很滿意的. 我一直但願能構建相似的題, 寓教於樂. 就當本身一個之後奮鬥的方向吧! 與君共勉.
公衆號&遊戲站點:
我的微信公衆號: 木目的H5遊戲世界
我的遊戲做品集站點(尚在建設中...): www.mmxfgame.com, 也可直接ip訪問: http://120.26.221.54/.