目录
- 任意URL重定向防护
- XSS过滤
- SQL注入过滤
- 个人敏感信息脱敏处理
- 综合建议
以普通程序员的角度实现这些安全功能,然后从安全测试者的角度去分析可能的绕过方法。
任意URL重定向防护
- 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
-
- # 默认允许当前域名和子域名
- if allowed_domains is None:
- # 在实际应用中应该从配置获取或设置为空
- allowed_domains = ["example.com", "*.example.com"]
-
- # 解析URL
- parsed = urlparse(url)
-
- # 检查是否为相对路径
- if not parsed.netloc:
- # 相对路径是安全的
- return url
-
- # 检查协议
- 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:协议绕过: javascript:alert(1)
- 使用双斜杠绕过: //evil.com
- 使用数据URI: data:text/html,
- 利用子域名解析漏洞: 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转义
- 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 = '<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)>
复制代码 安全测试者视角:
- 大小写绕过:
- 使用HTML实体编码: <script>alert(1)</script> (如果解码不当)
- 使用JavaScript伪协议: javascript:alert(1)
- 利用事件处理程序: (如果过滤不完整)
- 使用SVG标签:
SQL注入过滤
- import re
- def sanitize_sql(input_str):
- """
- 基本的SQL注入过滤
- :param input_str: 用户输入
- :return: 过滤后的安全字符串
- """
- if not input_str:
- return ""
-
- # 移除常见的SQL关键字
- sql_keywords = ['union', 'select', 'insert', 'update', 'delete', 'drop',
- 'exec', 'execute', 'where', 'or', 'and', 'like', 'sleep',
- 'benchmark', '--', '/*', '*/', ';', "'", '"']
-
- sanitized = input_str
- for keyword in sql_keywords:
- # 使用正则表达式进行不区分大小写的匹配和替换
- pattern = re.compile(re.escape(keyword), re.IGNORECASE)
- sanitized = pattern.sub('', sanitized)
-
- return sanitized
- # 更好的做法是使用参数化查询
- def safe_query(cursor, query, params):
- """
- 使用参数化查询防止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
- 使用非标准空格: 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 (全角数字)
- 使用HTML实体编码: 13812345678
- 使用零宽字符: 13812345678
- 拆分敏感信息: "手机号是138" + "1234" + "5678"
综合建议
从安全测试者的角度来看,没有任何单一防护措施是完美的。最佳实践包括:
- 多层防御: 在应用的各个层面实施安全措施
- 白名单策略: 优先使用白名单而非黑名单
- 参数化查询: 对于SQL注入,始终使用参数化查询
- 内容安全策略(CSP): 对于XSS,实施CSP头部
- 定期安全测试: 定期进行渗透测试和代码审计
- 使用安全库: 使用经过验证的安全库而不是自己实现
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |