如何防护PHP页面免受SQL注入并实现指定URL伪静态?
解决URL重写与SQL注入防护问题
一、修复URL重写(.htaccess)问题
你的现有规则有几个细节问题导致未生效,我帮你调整优化一下:
1. 正确的.htaccess规则(需放在abc目录下)
把原来的代码替换成下面的配置:
Options +FollowSymLinks RewriteEngine On # 将友好URL重写为实际PHP路径 RewriteRule ^read_story/([0-9]+)$ read_story.php?story_id=$1 [QSA,L] # 可选:强制跳转原动态URL到友好URL(优化SEO与用户体验) RewriteCond %{THE_REQUEST} ^GET.*read_story\.php\?story_id=([0-9]+) [NC] RewriteRule ^ read_story/%1? [R=301,L]
2. 原规则失效的原因
- 你添加了
.html后缀,但目标URL是read_story/3无后缀,导致规则无法匹配 - 使用绝对URL会触发外部跳转,改用相对路径更适配服务器配置
- 限定
[0-9]+比[0-9a-zA-Z]+更精准,因为story_id是数字ID,减少无效匹配范围
3. 确保服务器支持重写
- 确认Apache的
mod_rewrite模块已启用(可通过phpinfo()查看模块列表) - 检查站点或
abc目录的Apache配置,将AllowOverride设为All,否则.htaccess规则会被忽略:
<Directory "/path/to/your/abc"> AllowOverride All </Directory>
二、防护SQL注入攻击
除了URL美化,必须从代码层面彻底阻断SQL注入风险,核心措施如下:
1. 使用预处理语句(Prepared Statements)
绝对不要直接拼接SQL语句,用PDO或mysqli的预处理功能是最可靠的方式:
PDO示例:
<?php $story_id = $_GET['story_id']; // 额外防护:强制转换为整数,过滤非数字输入 $story_id = intval($story_id); try { $pdo = new PDO('mysql:host=localhost;dbname=your_database', 'username', 'password'); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $stmt = $pdo->prepare("SELECT * FROM stories WHERE id = ?"); $stmt->execute([$story_id]); $story = $stmt->fetch(PDO::FETCH_ASSOC); } catch(PDOException $e) { echo "查询错误: " . $e->getMessage(); } ?>
mysqli示例:
<?php $story_id = $_GET['story_id']; $story_id = intval($story_id); $conn = mysqli_connect("localhost", "username", "password", "your_database"); if (!$conn) { die("连接失败: " . mysqli_connect_error()); } $stmt = mysqli_prepare($conn, "SELECT * FROM stories WHERE id = ?"); mysqli_stmt_bind_param($stmt, "i", $story_id); // "i"表示参数为整数类型 mysqli_stmt_execute($stmt); $result = mysqli_stmt_get_result($stmt); $story = mysqli_fetch_assoc($result); mysqli_stmt_close($stmt); mysqli_close($conn); ?>
2. 严格验证输入
- 因为
story_id是数字ID,用intval()强制转换为整数,即使传入恶意字符串也会被转为0,从源头过滤风险 - 永远不要信任任何用户输入(包括URL参数、表单数据等),始终做类型或格式验证
3. 废弃危险函数
停止使用已被官方废弃的mysql_*系列函数,它们没有预处理支持,安全性极低,且不再维护。
内容的提问来源于stack exchange,提问作者Azad Shedge
相关产品推荐
相关产品推荐

