以普通程序員的角度實現(xiàn)這些安全功能,然后從安全測試者的角度去分析可能的繞過方法。
任意URL重定向防護(hù)
import re
from urllib.parse import urlparse, urljoin
def safe_redirect(url, allowed_domains=None):
"""
安全的URL重定向驗證
:param url: 要重定向的URL
:param allowed_domains: 允許的重定向域名列表
:return: 安全的URL或None
"""
if not url:
return None
# 默認(rèn)允許當(dāng)前域名和子域名
if allowed_domains is None:
# 在實際應(yīng)用中應(yīng)該從配置獲取或設(shè)置為空
allowed_domains = ["example.com", "*.example.com"]
# 解析URL
parsed = urlparse(url)
# 檢查是否為相對路徑
if not parsed.netloc:
# 相對路徑是安全的
return url
# 檢查協(xié)議
if parsed.scheme not in ('http', 'https', ''):
return None
# 檢查域名是否在白名單中
domain_allowed = False
for allowed in allowed_domains:
if allowed.startswith('*.'):
# 通配符子域名匹配
base_domain = allowed[2:]
if parsed.netloc.endswith('.' + base_domain) or parsed.netloc == base_domain:
domain_allowed = True
break
else:
# 精確匹配
if parsed.netloc == allowed:
domain_allowed = True
break
if not domain_allowed:
return None
return url
# 使用示例
redirect_url = safe_redirect("https://evil.com", ["example.com"])
print(redirect_url) # 輸出: None
safe_url = safe_redirect("/dashboard", ["example.com"])
print(safe_url) # 輸出: /dashboard
安全測試者視角:
- 使用
javascript:協(xié)議繞過:javascript:alert(1) - 使用雙斜杠繞過:
//evil.com - 使用數(shù)據(jù)URI:
data:text/html,<script>alert(1)</script> - 利用子域名解析漏洞:
example.com.evil.com - 使用URL編碼:
%68%74%74%70%3a%2f%2f%65%76%69%6c%2e%63%6f%6d
XSS過濾
import html
def sanitize_input(input_str):
"""
基本的XSS過濾
:param input_str: 用戶輸入
:return: 過濾后的安全字符串
"""
if not input_str:
return ""
# HTML轉(zhuǎn)義
sanitized = html.escape(input_str)
# 移除危險屬性 (簡單示例)
dangerous_attributes = ['onload', 'onerror', 'onclick', 'onmouseover']
for attr in dangerous_attributes:
sanitized = re.sub(rf'{attr}\s*=', 'xss-removed=', sanitized, flags=re.IGNORECASE)
return sanitized
# 使用示例
user_input = '<script>alert("XSS")</script><img src=x onerror=alert(1)>'
safe_output = sanitize_input(user_input)
print(safe_output) # 輸出: <script>alert("XSS")</script><img src=x xss-removed=alert(1)>
安全測試者視角:
- 大小寫繞過:
<ScRipt>alert(1)</ScRipt> - 使用HTML實體編碼:
<script>alert(1)</script>(如果解碼不當(dāng)) - 使用JavaScript偽協(xié)議:
javascript:alert(1) - 利用事件處理程序:
<img src=x onerror=alert(1)>(如果過濾不完整) - 使用SVG標(biāo)簽:
<svg onload=alert(1)>
SQL注入過濾
import re
def sanitize_sql(input_str):
"""
基本的SQL注入過濾
:param input_str: 用戶輸入
:return: 過濾后的安全字符串
"""
if not input_str:
return ""
# 移除常見的SQL關(guān)鍵字
sql_keywords = ['union', 'select', 'insert', 'update', 'delete', 'drop',
'exec', 'execute', 'where', 'or', 'and', 'like', 'sleep',
'benchmark', '--', '/*', '*/', ';', "'", '"']
sanitized = input_str
for keyword in sql_keywords:
# 使用正則表達(dá)式進(jìn)行不區(qū)分大小寫的匹配和替換
pattern = re.compile(re.escape(keyword), re.IGNORECASE)
sanitized = pattern.sub('', sanitized)
return sanitized
# 更好的做法是使用參數(shù)化查詢
def safe_query(cursor, query, params):
"""
使用參數(shù)化查詢防止SQL注入
"""
cursor.execute(query, params)
return cursor.fetchall()
# 使用示例
user_input = "admin' OR 1=1--"
safe_input = sanitize_sql(user_input)
print(safe_input) # 輸出: admin OR 1=1
安全測試者視角:
- 雙重編碼繞過:
admin%2527%20OR%201=1-- - 使用注釋拆分:
/*!UNION*/ SELECT/*!*/ - 使用異或操作:
' OR '1'='1' XOR '1'='0 - 使用URL編碼:
%75%6e%69%6f%6e%20%73%65%6c%65%63%74 - 使用非標(biāo)準(zhǔn)空格:
UNION%0bSELECT
個人敏感信息脫敏處理
import re
def desensitize_info(text):
"""
個人敏感信息脫敏處理
:param text: 包含敏感信息的文本
:return: 脫敏后的文本
"""
if not text:
return text
# 身份證號脫敏 (保留前4后4位)
text = re.sub(r'(\d{4})\d{10}(\d{4})', r'\1******\2', text)
# 手機號脫敏 (保留前3后4位)
text = re.sub(r'(\d{3})\d{4}(\d{4})', r'\1****\2', text)
# 銀行卡號脫敏 (保留前6后4位)
text = re.sub(r'(\d{6})\d{8,10}(\d{4})', r'\1********\2', text)
# 郵箱脫敏
text = re.sub(r'(\w{2})[\w.-]*@(\w{2}[\w.-]*)', r'\1****@\2', text)
# 姓名脫敏 (保留姓氏)
text = re.sub(r'([\u4e00-\u9fa5]{1})[\u4e00-\u9fa5]+', r'\1**', text)
return text
使用示例
sensitive_text = "張三的手機號是13812345678,身份證是510123199001011234,郵箱是zhangsan@example.com"
desensitized_text = desensitize_info(sensitive_text)
print(desensitized_text)
# 輸出: 張**的手機號是138****5678,身份證是5101****1234,郵箱是zh****@example.com
安全測試者視角:
- 使用特殊格式繞過: 身份證號中使用空格或連字符
510123-19900101-1234 - 使用全角字符: 13812345678 (全角數(shù)字)
- 使用HTML實體編碼: 13812345678
- 使用零寬字符: 138?1234?5678
- 拆分敏感信息: "手機號是138" + "1234" + "5678"
綜合建議
從安全測試者的角度來看,沒有任何單一防護(hù)措施是完美的。最佳實踐包括:
- 多層防御: 在應(yīng)用的各個層面實施安全措施
- 白名單策略: 優(yōu)先使用白名單而非黑名單
- 參數(shù)化查詢: 對于SQL注入,始終使用參數(shù)化查詢
- 內(nèi)容安全策略(CSP): 對于XSS,實施CSP頭部
- 定期安全測試: 定期進(jìn)行滲透測試和代碼審計
- 使用安全庫: 使用經(jīng)過驗證的安全庫而不是自己實現(xiàn)
浙公網(wǎng)安備 33010602011771號