實戰用Python解析出抽象語法樹
生成抽象語法樹的例子
SQL
利用python的sqlparse庫
sqlparse 是一個用于解析和分析 SQL 語句的 Python 庫。它提供了一系列功能,可用于解析和操作 SQL 語句的不同組成部分,如關鍵字、標識符、表達式、函數、注釋等。
以下是 sqlparse 庫的一些主要功能:
解析 SQL 語句
sqlparse 可以解析和分析 SQL 語句,并將其拆分為不同的標記(token)。這使得您可以訪問和操作 SQL 語句的各個部分,如 SELECT 語句中的列、表名、WHERE 子句等。
以sql代碼SELECT * FROM users WHERE id = '1' OR '1'='1' or (1=2) or (x = '(123)')為例,編寫了如下示例:
import sqlparse
# 遞歸打印 SQL 解析樹
def print_tokens(tokens, indent=0):
for token in tokens:
if hasattr(token, "tokens"):
print_tokens(token.tokens, indent + 4)
else:
print(" " * indent,token.ttype, token.value)
# 解析 SQL 查詢語句
def demo1():
user_input = "1' OR '1'='1"
sql_query = "SELECT * FROM users WHERE id = '" + user_input + "' or (1=2) or (x = '(123)')"
print(sql_query)
parsed = sqlparse.parse(sql_query)[0]
# 打印 AST 對象
print_tokens(parsed.tokens)
if __name__ == '__main__':
demo1()
運行的結果為:
Token.Keyword.DML SELECT
Token.Text.Whitespace
Token.Wildcard *
Token.Text.Whitespace
Token.Keyword FROM
Token.Text.Whitespace
Token.Name users
Token.Text.Whitespace
Token.Keyword WHERE
Token.Text.Whitespace
Token.Name id
Token.Text.Whitespace
Token.Operator.Comparison =
Token.Text.Whitespace
Token.Literal.String.Single '1'
Token.Text.Whitespace
Token.Keyword OR
Token.Text.Whitespace
Token.Literal.String.Single '1'
Token.Operator.Comparison =
Token.Literal.String.Single '1'
Token.Text.Whitespace
Token.Keyword or
Token.Text.Whitespace
Token.Punctuation (
Token.Literal.Number.Integer 1
Token.Operator.Comparison =
Token.Literal.Number.Integer 2
Token.Punctuation )
Token.Text.Whitespace
Token.Keyword or
Token.Text.Whitespace
Token.Punctuation (
Token.Name x
Token.Text.Whitespace
Token.Operator.Comparison =
Token.Text.Whitespace
Token.Literal.String.Single '(123)'
Token.Punctuation )
可以發現,sqlparse將SQL拆分成了一個一個token,在語法和詞法解析領域,Token(記號)是指源代碼中的最小語義單元,它代表了編程語言中的一個詞法元素。Token 是語法分析器(Parser)在解析源代碼時所使用的基本單位。
在編程語言中,Token 可以表示關鍵字、標識符、操作符、常量、字符串、注釋等各種語法成分。語法分析器通過詞法分析(Lexical Analysis)將源代碼分解為一系列的 Token,以便進行進一步的語法分析和語義處理。
詞法分析器(也稱為詞法解析器或掃描器)負責將源代碼字符串轉換為一系列 Token。它通過掃描源代碼字符流,識別出連續的字符組成的詞法單元,并為每個詞法單元分配一個相應的 Token 類型。每個 Token 類型通常具有一個唯一的標識符和相關的屬性值。
例如,在下面的代碼片段中:
x = 10 + y
詞法分析器將識別出以下 Token:
- 標識符 Token:x
- 操作符 Token:=
- 數字常量 Token:10
- 操作符 Token:+
- 標識符 Token:y
詞法分析器將將這些 Token 傳遞給語法分析器,后者負責根據語法規則進行進一步的解析和分析。
通過使用 Token,語法分析器可以更容易地理解和處理源代碼的結構。每個 Token 都包含了與之相關的類型信息和屬性值,使得語法分析器能夠根據 Token 類型進行相應的語法規則匹配和語義處理。
在拿到這棵詞法解析樹之后,不管sql注入如何變幻,我們都可以定位到最小token單元,從而動態監測sql注入的行為。
格式化 SQL 語句
sqlparse 可以根據預定義的樣式規則對 SQL 語句進行格式化。這使得 SQL 語句的結構更加清晰可讀,便于理解和調試。
當使用 sqlparse 庫來格式化 SQL 語句時,它會執行以下操作:
- 重新縮進:sqlparse 會根據語句的嵌套結構重新縮進語句,使其更具可讀性和結構清晰。它會根據語句中的關鍵字、括號、逗號等進行縮進操作,以反映語句的層次結構。
- 關鍵字大小寫轉換:sqlparse 可以根據指定的選項將關鍵字轉換為特定的大小寫形式。您可以選擇將關鍵字轉換為大寫、小寫或首字母大寫。這可以使 SQL 語句中的關鍵字在格式化后保持一致性。
- 空格和換行符處理:sqlparse 會添加適當的空格和換行符,以提高語句的可讀性。它會在逗號、括號、運算符等符號周圍添加空格,使語句更易于理解。此外,它會根據語句的結構添加適當的換行符,以使語句在屏幕上更好地展示。
- 注釋處理:sqlparse 會解析 SQL 語句中的注釋,并根據注釋的位置將其正確地應用于格式化的結果。這有助于確保注釋在格式化后保持正確的位置和格式。
- 字符串處理:sqlparse 會解析和處理 SQL 語句中的字符串,以確保在格式化后字符串的內容保持不變。它會保留字符串中的引號和轉義字符,以保持字符串的完整性。
下面是一個例子:
def demo2():
sql_statement = 'select * from users where deleted_mark = false '
formatted_sql = sqlparse.format(sql_statement, reindent=True, keyword_case='upper')
print(formatted_sql)
上述代碼中,我們的sql語句為select * from users where deleted_mark = false,最終的結果為:
SELECT *
FROM users
WHERE deleted_mark = FALSE
分析 SQL 語句結構
sqlparse 可以分析 SQL 語句的結構,并提供了一組 API 用于查找和操作特定類型的 SQL 元素。例如,您可以使用 sqlparse 查找和訪問所有的表名、列名、函數調用等。
過濾 SQL 片段
sqlparse 可以根據指定的條件過濾和選擇 SQL 語句中的特定部分。例如,您可以使用 sqlparse 僅提取 SELECT 語句中的列名,或者僅提取 WHERE 子句中的條件表達式。
解析 SQL 片段
sqlparse 不僅可以解析完整的 SQL 語句,還可以解析和分析 SQL 片段。這使得您可以處理和操作 SQL 片段而不僅僅是完整的語句。
python
ast庫解析python代碼
def demo3():
import ast
code = """
def greet(name=123):
print(f"Hello, {name}!")
return 1
"""
tree = ast.parse(code)
class MyVisitor(ast.NodeVisitor):
def visit_FunctionDef(self, node):
print("Function definition:", node.name)
# 獲取參數名和默認值
for arg in node.args.args:
print("Parameter name:", arg.arg)
# 獲取返回值
for statement in node.body:
if isinstance(statement, ast.Return):
print("Return value:", ast.literal_eval(statement.value))
self.generic_visit(node)
visitor = MyVisitor()
visitor.visit(tree)
運行的結果為
Function definition: greet
Parameter name: name
Return value: 1