一,用到的软件
vscode:php开发
phpstudy:php搭建环境
二,前提
在phpstudy上搭建环境,还有可视化的数据库,当然也可以在数据库bin目录cmd后,写mysql –uroot –p申请登录数据库,在输入密码就进入了mysql
html,css,js都是一类东西,即负责编写静态网页,也就是他们编写出来的东西是不能变化的,既定的,他们无法从数据库中调取数据,那么如何满足用户的即时需求呢,就需要用到php代码,他可以连接数据库,从数据库中调取数据返回给客户,所以他们四个是互相配合的,html里可以写php,php里也可以写html
三,数据库配置文件
每次要用php连接数据库时都要写一遍连接代码很麻烦,所以我们可以直接把连接数据库的代码写入一个新的文件,要连接数据库时,直接用include(“文件路径””)函数引用这个文件,节省时间,这个文件就叫数据库配置文件, 它保存了连接到数据库所需的所有信息,比如数据库的地址、用户名、密码等
四,get请求
$i=$_GET['id']; //get接受id的值传
$sql = "SELECT id, name, age from student where id=$i";;
get接受id的值并传给变量i,变量i再赋值给id, 访问http://localhost/text/index.php?id=1,即可传参id=1,此时就产生了sql注入漏洞,即如果传参写成了http://localhost/text/index.php?id=1 union select 1,2,3 from admin,没有防御的情况下,查询语句就会变成SELECT id, name, age from student where id= 1 union select 1,2,3 from admin
五,post,request请求
格式与get的一样,不过post不能通过像get那样通过url直接传参给服务器,而request代表着接受所有,可以接受url直接传参
$_post['id']
$_REQUEST['id']
$p=$_REQUEST['y'];
echo $p;
六,echo
$p=1
echo $p
输出的是变量p的值,即1
echo ‘$p’
输出的是
p
echo ‘x=$p’
输出的是x=$p
echo "x=$p"
输出的是x=1
双引号会解析变量,单引号不会
六,请求大全
$_GET['id']
接受get传参
$_REQUEST['id']
接受get,post,cookie传参
$_post['id']
接受post传参
$_COOKIE['id']
接受cookie数据
$_ENV['id']
接受环境变量
$_FILES['id']
接受文件上传
$_SERVER['id']
接受服务器变量
$_SESSION['id']
接受session数据
cookie和session一般用来处理身份验证,server接受浏览器信息,访问地址等信息,比如手机端和电脑端发送的信息就不一样,server接受后返回不同的页面
七,文件上传
html用于编写文件上传页面,php用于接收
三种文件上传代码
①自写文件上传代码②编辑器③框架类
后两种可以查到有没有漏洞,没有就是没有,第一种就要自己判断
八,文件下载
前提:网站上提供了不同的可以下载的项目,用户通过提交文件名来选择下载哪个
直连下载
http://www.xiaodi8.com/soft/软件.zip
$url='http://'.$_SERVER['HTTP_HOST'].'blog/file/soft/'.$name;
_SERVER['HTTP_HOST']用于获取当前请求的主机名(hostname),即www.xiaodi8.com/soft ,而name则是用户提交的文件名
header("location: $url");
直接重定向到这个地址
根据浏览器配置的MIME类型,检测到要访问exe或者zip文件,就会自动显示下载
直连下载为什么安全:
通过修改$name为php文件只能跳转到对应网站,而不能下载
传参下载
http://www.xiaodi8.com/soft/down.php?filename=软件.zip
危险:通过传递参数,再将参数传入对应下载函数来下载文件,此时如果修改参数值为php文件,就会直接下载php文件,造成泄露风险
文件删除
unlink()删除文件
rmdir()删除文件夹
文件读取
文件包含
将指定文件包含到当前脚本中,有include('文件路径'),require('文件路径'),include_once('文件路径')等
比如包含数据库配置文件,就可以调用数据库
在网页上的显示是,被包含文件的内容会直接插入到当前脚本的相应位置,并作为当前脚本的一部分执行。
当然可以把文件路径设为一个可输入数据,在客户端上由用户输入数据
两种模式
本地包含:是指包含同一服务器上的文件。这是最常见和最安全的包含方式
远程包含:是指通过 URL 包含另一个服务器上的文件,如
include('http://example.com/header.php')
搜索框
$s=$_POST['search'];
$sql="select * from sy_guestbook where gName like '%$s%'"; *//%是通配符,意思是只要*gName值*中间有$s就可以*
$result=mysql_query($sql,$conn);
echo '你搜索的'."'$s'".'结果如下:';
容易产生xss漏洞:搜索框输入js代码,会执行该代码
留言板
原理:每次刷新都会将数据库数据显示出来,插入新的留言时,现将数据插入到数据库,再把所有数据显示出来
漏洞:内容一栏输入js代码
只要刷新,就弹一次窗,而搜索框则要点提交才有弹窗
原因:搜索框只是对数据库进行了数据搜索,而留言板每次刷新都会把留言数据提交到数据库里再显示出来.第一个叫反射型xss,第二个叫存储型xss
寻找xss漏洞
寻找能控制页面输出内容的地方,输入一个内容,网站会给你输出一个内容
PHP全局变量-$_SERVER
$_SERVER 是一个包含了诸如头信息(header)、路径(path)、以及脚本位置(script locations)等信息的 array
如$_SERVER['SERVER_NAME'];
从服务器配置中获取主机名,更可靠,结果:www.runoob.com
$_SERVER['HTTP_REFERER'] ;
链接到当前页面的前一个页面的url,反映在请求包里就是请求包的Referer值
$_SERVER["HTTP_X_FORWARDED_FOR"]
接收ip 应用价值:可以通过接受到的ip地址判断登陆者所处地理位置,判断能不能登录
在请求包里就是X-forwarded-For值
所以就可以绕过网站里的ip检测,但如果是服务器的协议检测ip,那就不可能绕过
$_SERVER['HTTP_HOST']
从 HTTP 请求头中的 Host
字段获取主机名,由客户端请求决定。可以被客户端伪造
csrf跨站点请求伪造
比如说:管理员管理的网站处于登录状态,且攻击者知道了管理员喜欢看的一个博客,并在其上植入了一个js代码网页,能获取其管理的网站的信息,管理员访问博客时会触发代码,攻击就实现了
登录验证
判断用户登录的思路
1.发送登录请求 账号 密码
2.接收账号密码
3.判断账号密码的准确性
正确 成功登陆->跳转成功页面
错误 失败登录->重新登陆
cookie,session
当浏览器存储下cookie后,在过期前登录这个网站都是不需要输密码的
cookie:身份验证 存储到客户端浏览器内
cookie安全:cookie修改 伪造 盗取
session:身份验证 存储到服务端服务器内
session安全:会话劫持(session劫持)
cookie运用实例
setcookie()函数
<?php
$user = 'John Doe';
setcookie('user', $user, 0, '/');
?>
在客户端浏览器中设置一个名为 user
的 cookie,值为 'John Doe'
,0表示过期时间为浏览器关闭后0秒,路径为 '/'
表示cookie 在整个网站的所有路径下都有效,如果设置为某个特定的路径,比如 '/admin'
,则这个 cookie 只在 /admin
路径及其子路径下有效。
登录一个网站的管理系统
输入账号密码>账号密码正确>跳转admin,这时候就有一个问题了,就是我们也可以直接通过url跳转admin文件(未授权访问),所以必须在跳转前加一个验证代码,证明我们的确是通过输入账号密码后才登录的,这里有两种验证方法,cookie和session
cookie验证:
思路:①登录成功后,执行setcookie()函数,为用户设置一个cookie值,再跳转admin文件
②此时,再写一个文件 ../config/login_check.php :这个文件用于验证cookie值是否为空
③此时重点来了,将admin文件直接改为include(../config/login_check.php), 所以跳转到admin文件后会再执行login_check.php代码,验证cookie值是否为空,如果不为空,就显示真正的admin界面,如果为空,就返回’没有权限’
$result=mysql_query($sql,$conn);
//接受账号和密码
if (mysql_num_rows($result))
//mysql_num_rows判断行数
{
//设置一个cookie键值对,即user=
setcookie('user',$username,0,'/');
username
header('Location: index.php');
}
根据这种方法,即使用户直接访问admin文件,也会强制执行cookie验证代码,从而防止了无授权访问,当然,这种方法也是有缺陷的,就是我们可以直接修改cookie的值达到无账号密码访问,还可以盗取cookie,别人可以通过xss漏洞执行js代码获取当前浏览器的所有cookie
session验证
session_start()有什么用:
session_start()
函数,用于启动会话。会话是一种在服务器端存储用户数据的机制,用于在多个页面之间保持用户的状态和数据,在启动会话后,会使用 $_SESSION
超全局变量来存储和访问会话数据,并在客户端的请求包中设置 PHPSESSID
的值
这里的SESSID是PHP版本的,所以是PHPSESSID,如果是jsp脚本,则是JSPSESSID
session_start()如何实现在在多个页面之间共享数据?
1. 启动会话
当在某个 PHP 页面中调用 session_start()
时,PHP 会检查客户端是否已经存在一个会话。如果存在,PHP 会恢复该会话;如果不存在,PHP 会创建一个新的会话。
2. 创建会话 ID
每个会话都有一个唯一的标识符,称为会话 ID。这个 ID 通常存储在客户端的 cookie 中(PHPSESSID),也就是说,客户端的请求包里可以看到一个PHPSESSID
键值对,如果客户端禁用了 cookie,PHP 也可以通过 URL 参数传递会话 ID。
3. 存储会话数据
会话数据存储在服务器端,通常在服务器的临时目录中。当调用 session_start()
时,PHP 会初始化一个数组 $_SESSION
,可以通过这个数组来存储和访问会话数据。
4. 数据共享
在多个页面之间共享数据时,每个页面都需要调用 session_start()
来启动会话。这样,每个页面都可以访问和修改同一个 $_SESSION
数组中的数据
5.备注
在多个页面之间共享数据时,每个页面发送的 PHPSESSID 是一样的,只要会话没有被销毁或超时。PHPSESSID 是用于标识会话的唯一 ID,通过这个 ID,服务器可以区分不同的客户端会话。
所以此时,我们就有了利用session验证登录的方法:
①即在login.php和admin.php两个文件中都要写一个session_start(); 在 login.php
中,session_start()
是为了在登录成功后存储用户的状态,可以把一个特殊变量加入到
_SESSION['username'] = row['username']`,这个值就是用来验证是否登录的.(注意,不添加的话初始_SESSION是空的)
②而在 admin.php
中,session_start()
是为了读取这些会话数据,验证用户是否已经登录,检查$_SESSION['username']是否等于admin,如果等于,就显示管理员网页的内容,如果不等于,就显示没有权限
③session验证相当于给服务器打电话,登陆之后相当于电话接通,一旦关闭浏览器会话就终止了,相当于电话挂断(每次登陆都会重新生成SESSID)
会话劫持:人家正在浏览器浏览,没有关闭,这时候获取的session是有效的,就可以伪造登录,如果他关了,那么获取到的session就没有任何价值
黑盒测试与白盒测试
黑盒不知道源代码,只能靠猜,白盒知道,如果知道了cookie验证的代码,就可以伪造cookie进行登录,如上述例子,输入一个错误的账号密码,抓包,此时根据他设置cookie的原理,我们的cookie值为空,所以修改cookie值不为空,在放包就可以实现登录
万能密码
SELECT * FROM sy_adminuser where username='' or 1=1# and password='dsadsaa';
假或真=真,#为注释号
验证码**(防止爆破)**
每次登录还需要输入验证码,就可以防止爆破攻击,当然同样存在缺陷:
用burpsuite抓包,发送到repeater模块,保持验证码正确不断更改密码直到成功
这个过程就相当于爆破
防爆破攻击:-每一次登录验证码都要变,否则有没有验证码没有区别
文件后缀名验证
这个功能可以由js或php实现,两种代码的区别如下:
php:验证的代码看不到,只能黑盒测试
js:验证的代码可以看到,白盒测试 ,所以可以让浏览器禁用js,来躲避js代码的验证
原因:php代码浏览器无法看到,只能查看HTML、CSS 和 JavaScript,这三者由服务器发送给浏览器浏览器再执行生成网页,而PHP 代码在服务器端执行,生成的 HTML、CSS 和 JavaScript 代码再发给浏览器
如何判断是哪种代码:
①f12看下有没有相关js代码,当然如果相关代码被包含了,那就没用了
②根据数据回显时间,js很快,php还得缓一下
Ajax
Ajax是一种在网页开发中常用的技术,可以传递数据,它允许网页在不重新加载整个页面的情况下,与服务器进行数据交换。这样可以实现更流畅的用户体验,因为页面的某些部分可以动态更新,而无需用户等待整个页面重新加载,本质上还是由js写的
工作原理
- 创建 XMLHttpRequest 对象:这是Ajax的核心,用于向服务器发送请求和接收响应。
- 发送请求:通过JavaScript向服务器发送请求,可以是GET或POST方法。
- 接收响应:服务器处理请求后返回数据,JavaScript接收这些数据。
- 更新页面:浏览器处理返回的数据,并更新网页的相应部分
示例场景
- 搜索框自动补全:在用户输入搜索关键词时,通过Ajax请求服务器,获取匹配的关键词列表并显示在搜索框下方。
- 动态加载更多内容:在社交媒体或新闻网站上,当用户滚动到页面底部时,通过Ajax加载更多内容。
通过ajax传递参数验证登录:
login.html
$.ajax({
//发给ajax.php文件。
type:'post',
url:'ajax.php',
dataType:'json',
data:{
myUname:$('.user').val(),
myUpass:$('.pass').val()
},
success:function (res) {
[//console.log](https://console.log/)(res);
if(res.infoCode==1){
alert('登录成功');
}else{
alert('登录失败');
浏览器先运行login.html,将myUname,myUpass两个参数传给服务器
ajak.php
$username=$_POST['myUname'];
$password=$_POST['myUpass'];
$success=array('msg'=>'ok');
if($username=='xiaodi' && $password=='123456'){
$success['infoCode'] = 1; //成功登录
}else{
$success['infoCode'] = 0; //失败登录
}
服务器再运行ajak.php,将infoCode值返回给浏览器,浏览器再运行login.html检验
漏洞:
可以修改返回包里的infoCode值来骗过浏览器
**提醒:**像这种由js代码判断是否登录成功的,即前端验证,都可以修改参数来绕过,而如果由后台php代码判断,直接会返回登录成功的页面,就不能修改参数 绕过了
**小技巧:**返回包中有json,code,msgbox等关键字,大部分为js前端验证
购物-设计
设计1:商品价格以前端设置价格为准。数据接收价格后运算
前端页面:user.html
$.ajax(
{
type:'post',
url:'shop.php',
dataType:'json',
data:
`{
price:'8888',
number:$('.num').val()`
`},
success:function (res)`
`{
if(res.code==1)`
`{
alert('购买成功');
}`
`else`
`{
alert('购买失败');`
`}`
`}`
}
shop.php——进行验证
$success=array('msg'=>'ok');
$price=$_POST['price'];
$num=$_POST['number'];
$m=$price*$num;
if($m<10000){
$success['code']=1;
}else{
$success['code']=0;
}
这两组代码规定了购买总额不能超过10000
绕过:
第一种方法:同上,Do intersept,更改code为1
第二种绕过方法:更改price=8
设计2:商品价格以数据库设置价格为准。接收价格后运算
代码:
小迪安全 第16天:php开发-个人博客项目&JS-Ajax&前端逻辑&购物&登录&上传_小迪安全php开发有必要看么-CSDN博客
此时抓包直接更改价格或数量依然会改变总金额,因为
$price=$_POST['price'];
$num=$_POST['number'];
这两行代码是直接接受浏览器post传参的,所以以数据库设置价格为准只是做了一个表面功夫
解决办法:
过滤数量