【14】WEB安全学习----PHP会话控制

一、会话控制简介

在前面学习了HTTP协议,知道了HTTP是无状态无连接的协议,为了解决无状态这个问题,通过在HTTP头部字段中的Cookie字段来标识当前连接用户标识。一个网站鉴别用户信息是通过CookieSession进行鉴别。

Cookie分为2种:

内存cookie:也叫做非持久Cookie,是保存在用户浏览器中,一旦浏览器关闭,内存中的cookie也会被丢失,但并未被销毁

硬盘cookie:也就做持久Cookie,是保存在用户硬盘中的,有过期时间,浏览器再次打开,通过读取硬盘中的Cookie信息保持持久化。

Session:

因为Cookie是保存在客户端中,为了鉴别用户,需要把用户相关信息如用户密码信息写入到Cookie中给客户端浏览器保存,这样如果加密不安全,则导致安全问题(篡改、拆解),而Session则有效解决了这个问题。Session信息是保存在服务器上,一个用户信息对应一个Session_ID,服务器只需要把Session_ID发送给客户端浏览器,服务器校检用户信息通过Session_ID找到对应的用户密码信息进行校检,有效提高了安全性。

二、PHP中Cookie操作

在PHP中,对Cookie的操作是用setcookie()函数,获取Cookie信息是用$_COOKIE超全局变量。

bool setcookie ( string $name [, string $value = "" [, int $expire = 0 [, string $path = "" [, string $domain = "" [, bool $secure = false [, bool $httponly = false ]]]]]] )

参数解释:

name:Cookie 的名称

value:Cookie的值

expire:Cookie的过期时间,采用时间戳表示

path:Cookie的有效服务器路径,如果设置了"/"为根路径,则表示对当前所有路径生效

domain:Cookie的有效域名,为了安全,一般设置了当前二级域名有效。

secure:如果设置为True,则Cookie信息只能通过HTTPS协议进行传递。

httponly:防止XSS攻击,设置为True,使JS脚本不能读取设置。

演示例子

<?php
	//设置Cookie
	$user='admin';
	$pwd='123456';
	setcookie('user',$user,time()+3600,"/","",False,True);
	setcookie('pwd',md5($pwd.'1q2w3e'),time()+3600,"/","",False,True);
	//读取Cookie
	echo $_COOKIE['user'].'<br />';
	echo $_COOKIE['pwd'];
	echo '<hr />';
	//修改COOKIE
	$user='root';
	setcookie('user',$user,time()+3600,"/","",False,True);
	//删除COOKIE:

	//1、可以通过设置过期时间使客户端浏览器COOKIE过期
        setcookie('user',$user,time()-2,"/","",False,True);
	setcookie('pwd',md5($pwd.'1q2w3e'),time()-2,"/","",False,True);
	//2、设置Cookie为空,会告知客户端浏览器删除Cookie
	setcookie('user','');
    //但以上两种,如果攻击者通过抓包工具提交COOKIE,不借助浏览器,Cookie将不会失效
?>

服务器通过Set-Cookie字段,将Cookie信息发送给客户端,以后客户端请求该信息会将此COOKIE附带提交。

三、PHP中Session操作

1、session_start()

会创建新会话或者重用现有会话。 如果通过 GET 或者 POST 方式,或者使用 cookie 提交了会话 ID, 则会重用现有会话。

<?php
	session_start();
?>

第一次访问,服务器会返回一个Session_ID给客户端

当服务器在次访问并附带此session_ID进行提交后,服务器校检此ID有效(存在),则不在返回新的ID。

2、Session操作

<?php
	session_start();
	if($_GET['pwd']=='admin'){
		$_SESSION['admin']='admin';
		$_SESSION['pwd']=md5('123456'.'1q2w3e');
	}
	//http://127.0.0.1/?pwd=admin
	print_r($_SESSION);  //Array ( [admin] => admin [pwd] => cb0d164dcffd1605ee9754ae48988164 )
	//销毁session会话
	session_destroy();
	$_SESSION='';
	print_r($_SESSION);
?>

四、实例操作

登陆表单-index.html

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>登陆</title>
</head>
<body>
    <form action="./login.php" method="post">
        用户名:<input type="text" name="user" id=""><br />
        密码:<input type="password" name="pwd" id=""><br />
        验证码:<input type="text" name="code" id=""><img src="code.php" onclick="this.src='code.php?'+new Date().getTime();" width="100" height="35">
        <input type="submit" name='submit' value="登陆">
    </form>
</body>
</html>

验证码-code.php

<?php
session_start();
//1.创建黑色画布
$image = imagecreatetruecolor(100, 30);
//2.为画布定义(背景)颜色
$bgcolor = imagecolorallocate($image, 255, 255, 255);
//3.填充颜色
imagefill($image, 0, 0, $bgcolor);
// 4.设置验证码内容
//4.1 定义验证码的内容
$content = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
//4.1 创建一个变量存储产生的验证码数据,便于用户提交核对
$captcha = "";
for ($i = 0; $i < 4; $i++) {
    // 字体大小
    $fontsize = 10;
    // 字体颜色
    $fontcolor = imagecolorallocate($image, mt_rand(0, 120), mt_rand(0, 120), mt_rand(0, 120));
    // 设置字体内容
    $fontcontent = substr($content, mt_rand(0, strlen($content)), 1);
    $captcha .= $fontcontent;
    // 显示的坐标
    $x = ($i * 100 / 4) + mt_rand(5, 10);
    $y = mt_rand(5, 10);
    // 填充内容到画布中
    imagestring($image, $fontsize, $x, $y, $fontcontent, $fontcolor);
}
$_SESSION["code"] = $captcha;
//4.3 设置背景干扰元素
for ($$i = 0; $i < 200; $i++) {
    $pointcolor = imagecolorallocate($image, mt_rand(50, 200), mt_rand(50, 200), mt_rand(50, 200));
    imagesetpixel($image, mt_rand(1, 99), mt_rand(1, 29), $pointcolor);
}
//4.4 设置干扰线
for ($i = 0; $i < 3; $i++) {
    $linecolor = imagecolorallocate($image, mt_rand(50, 200), mt_rand(50, 200), mt_rand(50, 200));
    imageline($image, mt_rand(1, 99), mt_rand(1, 29), mt_rand(1, 99), mt_rand(1, 29), $linecolor);
}
//5.向浏览器输出图片头信息
header('content-type:image/png');
//6.输出图片到浏览器
imagepng($image);
//7.销毁图片
imagedestroy($image);

登陆验证-login.php

<?php
header('content-type:text/html;charset=utf-8');
session_start();
if(isset($_POST['submit'])){
    $user=$_POST['user'];
    $pwd=$_POST['pwd'];
    $code= strtolower($_POST['code']);
    $code1= strtolower($_SESSION['code']);
    if(strcmp($code,$code1)!=0){
        echo '<script>alert("验证码错误");location.href="index.html"</script>';
    }else if($user=='admin' && $pwd=='123456'){
        $_SESSION['user']=$user;
        $_SESSION['key']=sha1($pwd);
        echo '<script>alert("登陆成功");location.href="home.php"</script>';
    }else{
        echo '<script>alert("用户名或密码错误");location.href="index.html"</script>';
    }
}

用户首页-home.php

<?php
header('content-type:text/html;charset=utf-8');
session_start();
if($_SESSION['user']=='admin' && $_SESSION['key']==sha1('123456')){
    echo '欢迎'.$_SESSION['user'];
    echo '<a href="loginout.php">注销</a>';
}else{
    echo '<script>location.href="index.html"</script>';
}

用户注销-loginout.php

<?php
header('content-type:text/html;charset=utf-8');
session_start();
session_destroy();
$_SESSION='';
echo '<script>alert("注销成功");location.href="index.html"</script>';

验证码重放攻击

在login.php页面中,对验证码错误或用户密码错误情况,没有做验证码注销操作,导致可利用同一验证码进行多次验证,这也是大多数开发者忽略的问题。

漏洞修复:

对登陆失败的情况下,注销当前session,如果检测到了无此sessionID就表示遇到了重放攻击

<?php
header('content-type:text/html;charset=utf-8');
session_start();
if(isset($_POST['submit'])){
    $user=$_POST['user'];
    $pwd=$_POST['pwd'];
    $code= strtolower($_POST['code']);
    if(empty($_SESSION['code'])){
        echo '<script>alert("检测到验证码重放攻击");location.href="index.html"</script>';
        exit;
    }
    $code1= strtolower($_SESSION['code']);
    if(strcmp($code,$code1)!=0){
        session_destroy();
        echo '<script>alert("验证码错误");location.href="index.html"</script>';
    }else if($user=='admin' && $pwd=='123456'){
        $_SESSION['user']=$user;
        $_SESSION['key']=sha1($pwd);
        echo '<script>alert("登陆成功");location.href="home.php"</script>';
    }else{
        session_destroy();
        echo '<script>alert("用户名或密码错误");location.href="index.html"</script>';
    }
}

固定会话攻击

虽然对登陆失败情况下进行了注销session,但是没有对登陆成功进行注销。再就是登陆前和登陆后采用的session是同一个,容易导致会话固定攻击。

漏洞修复:

登陆成功后,使用新的sessionID替换旧的sessionID。

session_regenerate_id():使用新生成的会话 ID 更新现有会话 ID

可看到,登陆成功后返回了新的sessionID标识

因为登陆成功后,已删除原sessionID,所以重放登陆也会被检测到。

猜你喜欢

转载自blog.csdn.net/a15803617402/article/details/82721738