网页闯关游戏(riddle webgame)--SQL注入的潘多拉魔盒

 

前言:
  以前编写了一个网页闯关游戏(相似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/.

相关文章
相关标签/搜索