egg.js会导致sql注入吗

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了egg.js会导致sql注入吗相关的知识,希望对你有一定的参考价值。

参考技术A 不会。
sql注入的检测方法一般采取辅助软件或网站平台来检测,软件一般采用sql注入检测工具jsky,网站平台就有亿思网站安全平台检测工具。MDCSOFT SCAN等。采用MDCSOFT-IPS可以有效的防御SQL注入,XSS攻击等。

Drupal V7.3.1 框架处理不当导致SQL注入

  这个漏洞本是2014年时候被人发现的,本着学习的目的,我来做个详细的分析。漏洞虽然很早了,新版的Drupal甚至已经改变了框架的组织方式。但是丝毫不影响对于漏洞的分析。这是一个经典的使用PDO,但是处理不当,导致SQL语句拼接从而导致注入的问题。从这个问题,以及以往我见过的很多的漏洞来看,我不得不说,代码底层做的再安全,过滤的再完全,如果程序员的一个不小心,也将会导致重大安全问题的出现。多少的编码绕过,逻辑漏洞正是不小心带来的问题。

  0x00 注入的定位

  首先我根据网络上已经出现过的EXP,然后进行追踪。无奈,这个框架实在太大,我在跟进的过程中,遇到了诸多的问题,甚至路由模式都没有搞的很明白。然后根据已有的漏洞细节,我迅速定位到了漏洞的发生点。

  在文件 \\modules\\user\\user.module 中 有 user_login_authenticate_validate() 函数,代码如下:

  

function user_login_authenticate_validate($form, &$form_state) {
  $password = trim($form_state[\'values\'][\'pass\']);
  if (!empty($form_state[\'values\'][\'name\']) && !empty($password)) {
    // Do not allow any login from the current user\'s IP if the limit has been
    // reached. Default is 50 failed attempts allowed in one hour. This is
    // independent of the per-user limit to catch attempts from one IP to log
    // in to many different user accounts.  We have a reasonably high limit
    // since there may be only one apparent IP for all users at an institution.
    if (!flood_is_allowed(\'failed_login_attempt_ip\', variable_get(\'user_failed_login_ip_limit\', 50), variable_get(\'user_failed_login_ip_window\', 3600))) {
      $form_state[\'flood_control_triggered\'] = \'ip\';
      return;
    }
    $account = db_query("SELECT * FROM {users} WHERE name = :name AND status = 1", array(\':name\' => $form_state[\'values\'][\'name\']))->fetchObject();

  //省略无关代码...

 

很明显,这里的SQL查询就是漏洞触发现场了,我们跟进db_query这个函数,代码如下:

  

function db_query($query, array $args = array(), array $options = array()) {
  if (empty($options[\'target\'])) {
    $options[\'target\'] = \'default\';
  }

  return Database::getConnection($options[\'target\'])->query($query, $args, $options);
}

继续跟进query函数:

  public function query($query, array $args = array(), $options = array()) {

    // Use default values if not already set.
    $options += $this->defaultOptions();

    try {
      // We allow either a pre-bound statement object or a literal string.
      // In either case, we want to end up with an executed statement object,
      // which we pass to PDOStatement::execute.
      if ($query instanceof DatabaseStatementInterface) {
        $stmt = $query;
        $stmt->execute(NULL, $options);
      }
      else {
        $this->expandArguments($query, $args);
        $stmt = $this->prepareQuery($query);
        $stmt->execute($args, $options);
      }
    //省略无关代码...

我们知道,如果在PHP连接MySQL数据库中,如果我们使用PDO进行预编译的话,我们的语句是无法改变原有的查询结构的,也就是说,注入的语句,无法进行查询,只能是当做字符串。从而从数据库查询层对注入做了彻底防御。那么这里是怎么产生问题的呢?

0x01 错误的处理导致的安全问题

  但是这里有个问题,就是当参数是数组的时候,就会用到expandArguments这个方法,然后这个方法由于处理不当会导致安全问题。

  函数代码如下:

  

  protected function expandArguments(&$query, &$args) {
    $modified = FALSE;

    // If the placeholder value to insert is an array, assume that we need
    // to expand it out into a comma-delimited set of placeholders.
    foreach (array_filter($args, \'is_array\') as $key => $data) {
      $new_keys = array();
      foreach ($data as $i => $value) {
        // This assumes that there are no other placeholders that use the same
        // name.  For example, if the array placeholder is defined as :example
        // and there is already an :example_2 placeholder, this will generate
        // a duplicate key.  We do not account for that as the calling code
        // is already broken if that happens.
        $new_keys[$key . \'_\' . $i] = $value;
      }

      // Update the query with the new placeholders.
      // preg_replace is necessary to ensure the replacement does not affect
      // placeholders that start with the same exact text. For example, if the
      // query contains the placeholders :foo and :foobar, and :foo has an
      // array of values, using str_replace would affect both placeholders,
      // but using the following preg_replace would only affect :foo because
      // it is followed by a non-word character.
      $query = preg_replace(\'#\' . $key . \'\\b#\', implode(\', \', array_keys($new_keys)), $query);

      // Update the args array with the new placeholders.
      unset($args[$key]);
      $args += $new_keys;

      $modified = TRUE;
    }

    return $modified;
  }

我们再来回顾一下之前的查询语句,

db_query("SELECT * FROM {users} WHERE name = :name AND status = 1", array(\':name\' => $form_state[\'values\'][\'name\']))

这个数组我们是可控的,首先在array_filter之后,使用foreach进行遍历,然后二轮遍历中创建了一个新的数组。接着把$query变量中的键,进行了替换,替换掉以后的内容是之前新数组键用 \', \'进行合并成的一个新的字符串。这样我们通过键来进行SQL注入就行的通了。注入语句将会通过拼接进入。

0x03 测试

可以看得很清楚,name数组中的两个键都被拼接进了SQL查询。

 

0x04 反思

 这里是挺有意思,也很常见的一个问题。我在开头的引言中也说了。本来是做好了处理的,但是却使用了拼接,导致可控的外部数据进入了SQL查询。类似这样的问题还很常见,当然了,这也为自己挖洞提供了思路,在挖洞越来越困难的当下,挖洞思路的变化显得十分重要了。

 

  

以上是关于egg.js会导致sql注入吗的主要内容,如果未能解决你的问题,请参考以下文章

参数真的足以防止 Sql 注入吗?

SQL注入知识讲解 简介 危害 防御

Knex.js 会阻止 sql 注入吗?

ios注入垃圾代码 风险

使用prepared statement来防止SQL注入会影响性能吗?

pikachu-SQL注入