python代码加密方案

news2024/11/24 8:57:08
为何要对代码加密?
python的解释特性是将py编译为独有的二进制编码pyc 文件,然后对pyc中的指令进行解释执行,但是pyc的反编译却非常简单,可直接反编译为源码,当需要将产品发布到外部环境的时候,源码的保护尤为重要。
常见的源码保护手段有如下几种:
  1. 发行.pyc文件  
  2. 代码混淆
  3. 使用py2exe
  4. 使用Cython

一、发行.pyc文件

pyc文件是一种二进制文件,由原生Python文件经过编译后所生成的,py文件编译成pyc文件后加载速度更快而且提高了代码的安全性。pyc的内容与python的版本相关,不同版本编译的pyc文件不一样。

1.1、编译.pyc文件

编译单个py:
python -m compileall xxx.py  # 把单个.py文件编译为字节码文件

pyc会生成在目录下的__pycache__下(前后有双下划线)
生成的文件名命名方式:源文件名.cpython-python版本.pyc
   
编译多个
python -m compileall /path/src/ # 批量生成字节码文件,/path/src/是包含.py文件名的路径
    
将.py文件转化为.pyc文件,实现代码隐藏的需要;.pyc文件的使用与.py文件的使用相同。
# 安装
pip install compileall2

import compileall

# compile_file编译单个文件
compileall.compile_file('main.py')

# compile_dir 函数编译文件夹下的py文件
compileall.compile_dir('Lib/', force=True)

# 使用多处理器编译
compileall.compile_dir('Lib/', workers=2)

1.2、反编译.pyc文件 (.pyc -> .py)

# 安装 uncompyle
pip install uncompyle

# 把 name.pyc 反编译成 name.py
uncompyle6 name.pyc > name.py

反编译多个文件:uncompyle6 -o . *.pyc

1.3、优缺点

优点:
  • 简单方便,提高了一点源码破解门槛
  • pyc 文件的加载速度比 py 文件快
  • 平台兼容性好,.py能在哪里运行,.pyc就能在哪里运行
不足:
  • 解释器兼容性差, .pyc只能在特定版本的解释器上运行
  • 有现成的反编译工具, 破解成本低

二、代码混淆

代码混淆是指在不改变代码逻辑的情况下,对代码结构进行变换,通过一些带有混淆性质的命名、注释等,使代码变得晦涩难懂,从而达到保护代码的作用。

可以这样下手:

  • 移除注释和文档。没有这些说明,在一些关键逻辑上就没那么容易明白了。

  • 改变缩进。完美的缩进看着才舒服,如果缩进忽长忽短,看着也一定闹心。

  • 在 tokens 中间加入一定空格。这就和改变缩进的效果差不多。

  • 重命名函数、类、变量。命名直接影响了可读性,乱七八糟的名字可是阅读理解的一大障碍。

  • 在空白行插入无效代码。这就是障眼法,用无关代码来打乱阅读节奏。

实现方法:

  1. 网站混淆:Oxyry Python Obfuscator - The most reliable python obfuscator in the world, 破解: https://www.cnblogs.com/Eeyhan/p/13154217.html

  2. 使用 pyobfuscate 库进行混淆   (2条消息) Python 源码混淆与加密_pyobfuscate_早起的python的博客-CSDN博客

优点:

  • 简单方便,提高了一点源码破解门槛

  • 兼容性好,只要源码逻辑能够做到兼容,混淆代码亦能

不足:

  • 只能对单个文件混淆,无法做到多个互相有联系的源码文件的联动混淆

  • 代码结构未发生变化,也能获取字节码,破解难度不大

三、打包

类似的还有pyinstaller、Nuitka

  • pyinstaller是通过设置key来对源码进行加密的;
  • nuitka则是将python源码转成C++(这里得到的是二进制的pyd文件,防止了反编译),然后再编译成可执行文件。 
  • py2exe 是一款将 Python 脚本转换为 Windows 平台上的可执行文件的工具。其原理是将源码编译为.pyc文件,加之必要的依赖文件,一起打包成一个可执行文件。

3.1、py2exe打包

使用py2exe进行打包的步骤:

1、编写入口文件。本示例中取名为hello.py:
print('Hello World')
 
2、编写setup.py
from distutils.core import setup
import py2exe
 
setup(console=['hello.py'])
 
3、生成可执行文件
python setup.py py2exe

 

优点:

  • 能够直接打包成 exe,方便分发和执行

  • 破解门槛比 .pyc 更高一些

不足:

  • 兼容性差,只能运行在 Windows 系统上

  • 生成的可执行文件内的布局是明确、公开的,可以找到源码对应的.pyc文件,进而反编译出源码

3.2、pyinstaller打包

1、安装pyinstaller

2、在Terminal下输入:“pyinstaller -F -w *.py” 就可以制作出exe。生成的文件放在同目录dist下。

常用选项​​​

-F(注意大写)是所有库文件打包成一个exe。不加-F参数生成一堆文件,但运行快,压缩后比单个exe文件还小一点点。 加-F参数生成一个exe文件,运行起来慢。
-D:默认选项,创建一个目录,包含exe文件以及大量依赖文件;
-a,–ascii   不包含 Unicode 字符集支持;
-d,–debug   产生 debug 版本的可执行文件;
-i: 后接图标文件名,后缀是.ico,表示用自定义图标生成exe程序
-c:默认选项,使用控制台(就是类似cmd的黑框);(仅对 Windows 有效);
-w: 生成的exe程序不带窗口执行(仅对 Windows 有效);
-o DIR,–out=DIR 指定 spec 文件的生成目录。如果没有指定,则默认使用当前目录来生成 spec 文件;
-p 表示你自己自定义需要加载的类路径,一般情况下用不到;
-n NAME,–name=NAME  指定项目(产生的 spec)名字。如果省略该选项,那么第一个脚本的主文件名将作为 spec 的名字;
-i  选择图标

示例:

book.py:

import webbrowser

url="https://blog.csdn.net/leiwuhen92?type=blog"
print("hello world")
webbrowser.open_new(url)

打包指令:

pyinstaller -F  -i test.ico.ico -w book.py

 

优点:

  • 隐藏源码
  • 方便一用户使用方便,不用再安装什么python啊,第三方包之类的。

缺点:

  • 打包超级慢,启动超级慢

  • 生成的exe比较大

  • 可以反编译  

    Python可执行文件反编译教程(exe转py)_python_脚本之家 (jb51.net)

     (6条消息) Python 反编译:pycdc工具的使用_小嗷犬的博客-CSDN博客

    在线Python pyc文件编译与反编译 (lddgo.net)

 3.3、Nuitka打包

使用python打包工具nuitka进行编译打包 - 知乎 (zhihu.com)

nuitka的作用是将python程序转换成C语言的可执行elf文件。这样在运行时就可以享受到C语言处理过程中的优化,提高速度。经测试,Nuitka打包后的exe比Pyinstaller打包后的exe运行速度提升30%

对于第三方依赖包较多的项目(比如需要import torch,tensorflow,cv2,numpy,pandas,geopy等等)而言,这里最好打包的方式是只将属于自己的代码转成C++,不管这些大型的第三方包!

指令:

python -m nuitka --standalone --show-memory --show-progress --nofollow-imports --plugin-enable=qt-plugins --follow-import-to=utils,src --output-dir=out --windows-icon-from-ico=./logo.ico demo.py

参数:
--standalone:方便移植到其他机器,不用再安装python
--show-memory --show-progress:展示整个安装的进度过程
--nofollow-imports:不编译代码中所有的import,比如keras,numpy之类的。
--plugin-enable=qt-plugins:我这里用到pyqt5来做界面的,这里nuitka有其对应的插件。
--follow-import-to=utils,src:需要编译成C++代码的指定的2个包含源码的文件夹,这里用,来进行分隔。
--output-dir=out:指定输出的结果路径为out。
--windows-icon-from-ico=./logo.ico:指定生成的exe的图标为logo.ico这个图标,这里推荐一个将图片转成ico格式文件的网站(比特虫)。
--windows-disable-console:运行exe取消弹框。这里没有放上去是因为我们还需要调试,可能哪里还有问题之类的。

 四、使用Cython

原理:先用cython将python语言代码转换为c语言代码,然后用c编译器(gcc)生成可执行文件或动态链接库。

4.1、Cpython介绍

Cython是一个编程语言,它通过类似Python的语法来编写C扩展并可以被Python调用,既具备了Python快速开发的特点,又可以让代码运行起来像C一样快,同时还可以方便地调用C library。
Cython是属于python的超集,用于编写python的c扩展语言。
  
pyx文件由 Cython 编译为.c文件,包含 python 扩展模块的代码。.c文件由 C 编译器编译为.so文件(或 Windows 上的.pyd)。
生成的.so文件或pyd文件是D语言(C/C++综合进化版本)生成的二进制文件,理论上很难反编译。

Note: 纯python源码被cython编译后,因为没有使用类型标注等cython语法,故编译后的动态链接库和可执行文件,主要依赖python的运行时,并不依赖C/C++运行时,主要由python解释器执行,多线程GIL的问题同样存在,性能提升有限,但对for循环、大的列表对象遍历性能有明显优化效果。

4.2、安装

# 安装cython
pip3 install --no-cache-dir -i https://pypi.tuna.tsinghua.edu.cn/simple cython
 
# 安装c编译器(linux需安装python-devel, gcc)
centos: yum install python-devel  gcc
ubuntu: apt-get install build-essential

4.3、使用

先用cython将python语言代码转换为c语言代码,然后用c编译器(gcc)生成可执行文件或动态链接库。
  
通过shell 或 python脚本的方式,将项目启动的入口py编译成可执行文件,将项目的其他.py文件编译成.so(__init__.py除外)

Note: __init__.py文件定义了python的包结构,为了使cython编译后的.so能按照正常路径import,__init__.py不能被编译,故为了保护代码,整个项目的所有__init__.py文件不建议放业务相关代码。

4.3.1、单个文件的编译示例-linux

目录结构如下:
test/
├── test.py
├── main.py

test.py:

def hello():
    print('hello!')

main.py:文件头的#!/usr/bin/python3.8标记是否程序启动文件

#!/usr/bin/python3.8
from test import hello
 
if __name__ == "__main__":
    hello()

4.3.1.1、将启动main.py编译成二进制可执行文件main

 main.py ---> main.c ---> main.o ---> main :

# step1: 将python代码翻译成c代码(main.py -> main.c)
cython -D -3 --directive always_allow_keywords=true --embed main.py
 
# step2: 将c代码编译为目标文件(main.c -> main.o)
gcc -c main.c -fPIC -fwrapv -O2 -Wall -fno-strict-aliasing -I /usr/include/python3.8 -L /usr/bin -lpython3.8 -o main.o
 
# step3: 将目标文件编译为二进制可执行文件(main.o -> main)
gcc main.o -I /usr/include/python3.8 -L /usr/bin -lpython3.8 -o main

 main.py ---> main.c ---> main:

# step1: 将python代码翻译成c代码(main.py -> main.c)
cython -D -3 --directive always_allow_keywords=true --embed main.py
 
# step2: 将c代码编译为二进制可执行文件(main.c -> main)
gcc main.c -I /usr/include/python3.8 -L /usr/bin -lpython3.8 -o main

4.3.1.2、将test.py编译为动态链接库test.so

test.py ---> test.c ---> test.so:

# step1: 将python代码翻译成c代码(test.py -> test.c)
cython -D -3 --directive always_allow_keywords=true test.py
 
# step2: 将c代码编译为linux动态链接库文件(test.c -> test.so)
gcc test.c -shared -pthread -fPIC -fwrapv -O2 -Wall -fno-strict-aliasing -I /usr/include/python3.8 -L /usr/bin -lpython3.8 -o test.so

 cython参数说明:

-D, --no-docstrings, Strip docstrings from the compiled module.
-o, --output-file <filename>   Specify name of generated C file
-2                             Compile based on Python-2 syntax and code semantics.
-3                             Compile based on Python-3 syntax and code semantics.

gcc参数说明:

-shared:
编译动态库时要用到

-pthread:
在Linux中要用到多线程时,需要链接pthread库

-fPIC:
作用于编译阶段,告诉编译器产生与位置无关代码(Position-Independent Code),
则产生的代码中,没有绝对地址,全部使用相对地址,故而代码可以被加载器加载到内存的任意
位置,都可以正确的执行。这正是共享库所要求的,共享库被加载时,在内存的位置不是固定的。

-fwrapv:
它定义了溢出时候编译器的行为——采用二补码的方式进行操作

-O参数
这是一个程序优化参数,一般用-O2就是,用来优化程序用的
-O2:
会尝试更多的寄存器级的优化以及指令级的优化,它会在编译期间占用更多的内存和编译时间。
-O3: 在O2的基础上进行更多的优化

-Wall:
编译时 显示Warning警告,但只会显示编译器认为会出现错误的警告

-fno-strict-aliasing:
“-fstrict-aliasing”表示启用严格别名规则,“-fno-strict-aliasing”表示禁用严格别名规则,当gcc的编译优化参数为“-O2”、“-O3”和“-Os”时,默认会打开“-fstrict-aliasing”。

-I (大写的i):
是用来指定头文件目录
-I /home/hello/include表示将/home/hello/include目录作为第一个寻找头文件的目录,寻找的顺序是:/home/hello/include-->/usr/include-->/usr/local/include

-l:
-l(小写的 L)参数就是用来指定程序要链接的库,-l参数紧接着就是库名,把库文件名的头lib和尾.so去掉就是库名了,例如我们要用libtest.so库库,编译时加上-ltest参数就能用上了

4.3.2、单个文件的编译示例-windows

windows系统使用cython需要确保已安装C/C++编译器且环境变量正确配置,cython能找到编译器。windows系统可使用MSVC(Microsoft Visual C/C++)或者clang编译器。 

将test.py编译为动态链接库test.pyd:
test.py ---> test.c ---> test.pyd:

# step1: 将python代码翻译成c代码(test.py -> test.c)
cython -D -3 --directive always_allow_keywords=true test.py
 
# step2: 将c代码编译为windows动态链接库文件(test.c -> test.pyd)
cythonize -i test.c

最后得到windows下的动态链接库文件test.cp39-win_amd64.pyd,还需要将文件名重命名为test.pyd。

cythonize参数说明:

-b, --build     build extension modules using distutils
-i, --inplace   build extension modules in place using distutils(implies -b),即将编译后的扩展模块直接放在与test.py同级的目录中。

 4.3.3、python编译可执行文件与动态链接库

 https://github.com/leiwuhen92/cython_test  

main.py:主函数入口

#!/usr/bin/python3.8
from test import hello
from compute import compute
 
if __name__ == "__main__":
    hello()
    compute.is_leap_year(1992)

test.py:

def hello():
    print('hello!')

compute/compute.py:

def is_leap_year(year):
    if year%4==0 and year%100!=0 or year%400==0:
        print(year,"是闰年")
    else:
        print(year,"不是闰年")
 
 
if __name__ == "__main__":
    is_leap_year(1992)

setup.py:

import pathlib
import shutil
from subprocess import Popen, PIPE, STDOUT
 
 
# python编译so
def py_to_so(py_to_so_list):
    """
    :param py_to_so_list:  py文件列表,例如[test.py,]
    :return:
    """
    for py_to_so_item in py_to_so_list:
        # 将python代码翻译成c代码
        basename = py_to_so_item[:-3]
        py_to_c = "cython -D -3 --directive always_allow_keywords=true --embed {}".format(py_to_so_item)
        pl = Popen(py_to_c, shell=True, stdout=PIPE, stderr=STDOUT)
        pl.communicate()[0].decode('utf-8', errors='ignore')
 
        # 将c代码编译为linux动态链接库文件(
        c_to_so = "gcc {} -shared -pthread -fPIC -fwrapv -O2 -Wall -fno-strict-aliasing -I /usr/include/python3.8 -L /usr/bin -lpython3.8 -o {}".format(basename + ".c", basename + ".so")
        p2 = Popen(c_to_so, shell=True, stdout=PIPE, stderr=STDOUT)
        p2.communicate()[0].decode('utf-8', errors='ignore')
 
 
def py_to_bin(py_to_bin_list):
    """
    :param py_to_bin_list: py文件列表,例如[main.py,]
    :return:
    """
    for py_to_bin_item in py_to_bin_list:
        basename = py_to_bin_item[:-3]
        # 将python代码翻译成c代码
        py_to_c = "cython -D -3 --directive always_allow_keywords=true --embed {}".format(py_to_bin_item)
        p1 = Popen(py_to_c, shell=True, stdout=PIPE, stderr=STDOUT)
        p1.communicate()[0].decode('utf-8', errors='ignore')
 
        # 将c代码编译为二进制可执行文件
        c_to_bin = "gcc {} -I /usr/include/python3.8 -L /usr/bin -lpython3.8 -o {}".format(basename + ".c", basename)
        p2 = Popen(c_to_bin, shell=True, stdout=PIPE, stderr=STDOUT)
        p2.communicate()[0].decode('utf-8', errors='ignore')
 
 
def clean_build(project):
    """
    清理编译文件夹中的文件
    :param project:
    :return:
    """
    # 清理py文件
    for i in project.glob("**/*.py"):
        if i.name != "__init__.py" or i.name != "setup.py":
            i.unlink()
 
    # 清理c文件
    for j in project.glob("**/*.c"):
        j.unlink()
 
    # 清理__pycache__文件夹
    for k in project.glob("**/__pycache__"):
        shutil.rmtree(k)
 
 
if __name__ == "__main__":
    # 源文件夹
    project_pathlib = pathlib.Path.cwd()
 
    py_to_bin_list = ["main.py"]
    py_to_bin(py_to_bin_list)
 
    py_to_so_list = ["test.py"]
    for py in project_pathlib.glob("**/*.py"):
        if py.name != "__init__.py" and py.name != "setup.py" and py.name != "main.py":
            py_to_so_list.append(str(py))
    py_to_so(py_to_so_list)
 
    clean_build(project_pathlib)

 4.4、优缺点

优点

  • 生成的二进制so(linux)或.pyd(windows)文件难以破解

  • 性能会提升

不足

  • 兼容性稍差,对于不同版本的操作系统,可能需要重新编译

  • 虽然支持大多数Python代码,但如果一旦发现部分代码不支持,完善成本较高

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/667388.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Guitar Pro是什么软件 Guitar Pro有什么用

相信玩吉他的朋友多多少少都听说过Guitar Pro这款软件&#xff0c;那大家知道Guitar Pro是什么软件&#xff1f;Guitar Pro有什么用呢&#xff1f;今天小编就和大家分享一下关于Guitar Pro这款吉他软件的相关内容。 一、Guitar Pro是什么软件 简单说Guitar Pro是一款吉他谱软…

Vue实现元素沿着坐标数组移动,超出窗口视图时页面跟随元素滚动

一、实现元素沿着坐标数组移动 现在想要实现船沿着下图中的每个河岸移动。 实现思路&#xff1a; 1、将所有河岸的位置以 [{x: 1, y: 2}, {x: 4, y: 4}, …] 的形式保存在数组中。 data() {return {coordinateArr: [{ x: 54, y: 16 }, { x: 15, y: 31 }, { x: 51, y: 69 }…

leetcode77. 组合(回溯算法-java)

组合 leetcode77. 组合题目描述解题思路代码演示 递归专题 leetcode77. 组合 来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 链接&#xff1a;https://leetcode.cn/problems/combinations 题目描述 给定两个整数 n 和 k&#xff0c;返回范围 [1, n] 中所有可能的 k 个…

量化交易:止盈策略与回测

我们买基金或股票的时候通常用最简单的策略进行决策&#xff1a;低买高卖&#xff0c;跌的多了就加仓拉低持有成本&#xff0c;达到收益率就卖出。 那么如何用代码表示这个策略呢&#xff1f;首先定义交易信号则是&#xff1a;0.5%时买入&#xff0c;目标止盈线是1.5%&#xf…

Java官方笔记12异常

Exception Definition: An exception is an event, which occurs during the execution of a program, that disrupts the normal flow of the programs instructions. the checked exception 比如&#xff0c;java.io.FileNotFoundException the error 比如&#xff0c;java.i…

Flink流批一体计算(2):Flink关键特性

目录 流式处理 丰富的状态管理 流处理 自定义时间流处理 有状态流处理 通过状态快照实现的容错 流式处理 在自然环境中&#xff0c;数据的产生原本就是流式的。无论是来自 Web 服务器的事件数据&#xff0c;证券交易所的交易数据&#xff0c;还是来自工厂车间机器上的…

优先级队列建立小根堆来解决前K个高频元素(TOP K问题)

目录 场景一&#xff1a;解决前K个高频元素需要解决如下几个问题&#xff1a; 优先级队列PriorityQueue 堆的定义 题目链接 场景二&#xff1a;亿万级数据取前TOP K / 后TOP K 数据 场景一&#xff1a;解决前K个高频元素需要解决如下几个问题&#xff1a; 1.记录每一个元…

【C++】4.工具:读取ini配置信息

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍读取ini配置信息。 学其所用&#xff0c;用其所学。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜欢的朋友可以关注一下&#xff0c;下次更新不迷路&…

医院PACS系统的发展历史

PACS全称Picture Archivingand Communication Systems。它是应用在医院影像科室的系统&#xff0c;主要的任务就是把日常产生的各种医学影像&#xff08;包括核磁&#xff0c;CT&#xff0c;超声&#xff0c;X光机&#xff0c;红外仪、显微仪等设备产生的图像&#xff09;通过各…

【工程应用八】终极的基于形状匹配方案解决(小模型+预生成模型+无效边缘去除+多尺度+各项异性+最小组件尺寸)...

我估摸着这个应该是关于形状匹配或者模版匹配的最后一篇文章了&#xff0c;其实大概是2个多月前这些东西都已经弄完了&#xff0c;只是一直静不下来心整理文章&#xff0c;提醒一点&#xff0c;这篇文章后续可能会有多次修改(但不会重新发文章&#xff0c;而是在后台直接修改或…

【MySQL 日志管理、备份与恢复】

目录 一、数据库备份的分类1、从物理与逻辑的角度1.1、物理备份: 对数据库操作系统的物理文件&#xff08;如数据文件&#xff0c;日志文件等&#xff09;的备份1.2、逻辑备份 2、从数据库的备份策略角度3、常见的备份方法3.1、物理冷备3.2、专用备份工具mysqldump 或者 mysqlh…

【Windows系统】windows服务

概述 Microsoft Windows 服务&#xff08;即&#xff0c;以前的 NT 服务&#xff09;使您能够创建在它们自己的 Windows 会话中可长时间运行的可执行应用程序。这些服务可以在计算机启动时自动启动&#xff0c;可以暂停和重新启动而且不显示任何用户界面。这种服务非常适合在服…

C++算法:多源最短路径(Floyd)

文章目录 前言一、Floyd算法二、代码实现总结 前言 前文单源最短路径Dijkstra中我们讨论了如何解决有向无环图的最短路径问题&#xff0c;Dijkstra只能解决一个起始点的问题&#xff0c;如果要解决每个顶点到任一顶点的最短路径呢&#xff1f;一个方法就是再循环一次&#xff…

ASEMI代理光宝高速光耦LTV-60L规格,LTV-60L封装

编辑-Z LTV-60L参数描述&#xff1a; 型号&#xff1a;LTV-60L 封装&#xff1a;LSOP-6 储存温度TST&#xff1a;-55~125℃ 工作温度TA&#xff1a;-40~105℃ 隔离电压VISO&#xff1a;5000VRMS 电源电压VCC&#xff1a;7V 平均正向输入电流IF&#xff1a;20mA 输入功…

电脑滤镜软件哪个好 滤镜调色有什么技巧

无论是图片还是视频&#xff0c;滤镜的作用都很大&#xff0c;通过滤镜改变色彩&#xff0c;能让图片或视频增加故事性和美感。电脑滤镜软件哪个好, 电脑滤镜软件有很多&#xff0c;这里我们主要介绍几款视频滤镜软件。滤镜调色有什么技巧&#xff1f;有模板的&#xff0c;我们…

api-hook,更轻量的接口测试工具

目录 前言 现状 api-hook优势 研发介绍 最后 前言 api-hook是一种轻量级的接口测试工具&#xff0c;它基于Python语言编写&#xff0c;可以通过配置文件定义接口测试用例&#xff0c;支持HTTP和HTTPS协议&#xff0c;并提供了灵活的校验机制和数据处理方式。 在网站的开发过…

Tailwindcss 入门

Tailwindcss 是一个功能类优先的 CSS 框架&#xff0c;通过 flex, pt-4, text-center 和 rotate-90 这种原子类组合快速构建网站&#xff0c;而不需要离开你的 HTML。就是记住原子类&#xff0c;不要再自己想 CSS 命名一股脑子写 HTMl 就行了&#xff01; 它与常规的 Bootstra…

佩戴舒适度极好的蓝牙耳机推荐,久戴不累的蓝牙耳机推荐

无论是在日常还是运动的场景下&#xff0c;我们通常都会选择佩戴着耳机&#xff0c;让我们能够释放压力&#xff0c;缓解枯燥的生活。可是&#xff0c;随着市面上的蓝牙耳机层出不穷、各种各样&#xff0c;导致很多小伙伴不知如何选购耳机了&#xff0c;下面我来给大家分享几款…

循踪讲述:成都的夜,有一盏灯为你亮

成都的夜晚总是这样&#xff0c;热闹而梦幻。霓虹灯下的酒吧一条街&#xff0c;你看着手里冒着蒸汽的小龙虾&#xff0c;却心里想着那个人。那个曾经一起在脚手架上挥汗如雨&#xff0c;携手走过平淡岁月&#xff0c;然后在灯红酒绿的生活里逐渐远离的人。 他&#xff0c;一个手…

【数据治理-06】做好数据分类分级,为数据安全有序流动保驾护航

我们常说人以类聚&#xff0c;物以群分&#xff0c;确实是这样&#xff0c;杜威说过“所有知识都是分类”&#xff01;很好理解&#xff0c;分类是认知经济&#xff0c;任何有效分类&#xff0c;都可以极大地节省我们的认知精力。数据分类分级具体说来&#xff0c;其实包含了2个…