CodeQL 文档

从用户控制的源构建的 LDAP 查询

ID: py/ldap-injection
Kind: path-problem
Security severity: 9.8
Severity: error
Precision: high
Tags:
   - security
   - external/cwe/cwe-090
Query suites:
   - python-code-scanning.qls
   - python-security-extended.qls
   - python-security-and-quality.qls

点击查看 CodeQL 存储库中的查询

如果使用字符串连接或字符串格式化构建 LDAP 查询或 DN,并且连接的组件包括未经任何适当清理的用户输入,则用户可能能够运行恶意 LDAP 查询。

建议

如果用户输入必须包含在 LDAP 查询或 DN 中,则应对其进行转义以避免恶意用户提供改变查询含义的特殊字符。在 Python2 中,用户输入应使用 `ldap.dn.escape_dn_chars` 或 `ldap.filter.escape_filter_chars` 进行转义,而在 Python3 中,用户输入应使用 `ldap3.utils.dn.escape_rdn` 或 `ldap3.utils.conv.escape_filter_chars` 进行转义,具体取决于受用户污染的组件。最佳做法是转义可能改变查询含义的过滤字符(https://tools.ietf.org/search/rfc4515#section-3)。

示例

在以下示例中,代码接受来自用户的 `username` 和 `dc`,然后将其用于构建 LDAP 查询和 DN。

第一个和第二个示例直接在 LDAP 查询的搜索过滤器和 DN 中使用未经清理的用户输入。恶意用户可以提供特殊字符来改变这些组件的含义,并搜索完全不同的值集。

from flask import request, Flask
import ldap


@app.route("/normal")
def normal():
    unsafe_dc = request.args['dc']
    unsafe_filter = request.args['username']

    dn = "dc={}".format(unsafe_dc)
    search_filter = "(user={})".format(unsafe_filter)

    ldap_connection = ldap.initialize("ldap://127.0.0.1")
    user = ldap_connection.search_s(
        dn, ldap.SCOPE_SUBTREE, search_filter)
from flask import request, Flask
import ldap3


@app.route("/normal")
def normal():
    unsafe_dc = request.args['dc']
    unsafe_filter = request.args['username']

    dn = "dc={}".format(unsafe_dc)
    search_filter = "(user={})".format(unsafe_filter)

    srv = ldap3.Server('ldap://127.0.0.1')
    conn = ldap3.Connection(srv, user=dn, auto_bind=True)
    conn.search(dn, search_filter)

在第三个和第四个示例中,用户提供的输入在包含在搜索过滤器或 DN 中之前进行了清理。这确保了查询的含义不会被恶意用户更改。

from flask import request, Flask
import ldap
import ldap.filter
import ldap.dn


@app.route("/normal")
def normal():
    unsafe_dc = request.args['dc']
    unsafe_filter = request.args['username']

    safe_dc = ldap.dn.escape_dn_chars(unsafe_dc)
    safe_filter = ldap.filter.escape_filter_chars(unsafe_filter)

    dn = "dc={}".format(safe_dc)
    search_filter = "(user={})".format(safe_filter)

    ldap_connection = ldap.initialize("ldap://127.0.0.1")
    user = ldap_connection.search_s(
        dn, ldap.SCOPE_SUBTREE, search_filter)
from flask import request, Flask
import ldap3
from ldap3.utils.dn import escape_rdn
from ldap3.utils.conv import escape_filter_chars


@app.route("/normal")
def normal():
    unsafe_dc = request.args['dc']
    unsafe_filter = request.args['username']

    safe_dc = escape_rdn(unsafe_dc)
    safe_filter = escape_filter_chars(unsafe_filter)

    dn = "dc={}".format(safe_dc)
    search_filter = "(user={})".format(safe_filter)

    srv = ldap3.Server('ldap://127.0.0.1')
    conn = ldap3.Connection(srv, user=dn, auto_bind=True)
    conn.search(dn, search_filter)

参考资料

  • ©GitHub, Inc.
  • 条款
  • 隐私