Email 信息安全
2020-02-11
简介
SMTP 会话中,发行方会通过 MAIL FROM 命令告诉收信方,这封邮件是谁发出的。
但是,由于邮件系统的设计上没有考虑如何对垃圾邮件进行有效防范,收信方需要一个机制来判断这封邮件的来源是否可靠。因此,人们提出了 SPF 方案:
- 每个邮件服务都需要为自己的发信域名在 DNS 中配置一下 SPF 记录(TXT 类型),记录值是出信 IP。
- 收信方拿到
MAIL FROM 地址之后,使用发信方 IP 地址和发信域 DNS 中记录的 IP 地址做一个比对。如果匹配,说明来源正确,否则,这封邮件可以被视为垃圾邮件,直接返回投递失败(硬退)。
该方案 2006 年提交到 Network Working Group 成为草案,然后 2014 年成为建议标准。
注意:SPF 只是验证了邮件确实是从发信域所在网络投递出来的,但是不能防止邮件伪造和欺诈。应该结合其他技术,如 DKIM(DomainKeys Identified Mail)和 DMARC(Domain-based Message Authentication, Reporting, and Conformance),一起增强电子邮件的安全性。
SPF 记录示例
dig +short txt qq.com
"v=spf1 include:spf.mail.qq.com -all"
dig +short txt spf.mail.qq.com
"v=spf1 include:qq-a.mail.qq.com include:qq-b.mail.qq.com include:qq-c.mail.qq.com include:biz-a.mail.qq.com include:biz-b.mail.qq.com include:biz-c.mail.qq.com include:biz-d.mail.qq.com -all"
dig +short txt qq-{a..c}.mail.qq.com biz-{a..d}.mail.qq.com
"v=spf1 ip4:101.226.139.0/25 ip4:101.91.43.0/25 ip4:101.91.44.128/25 ip4:112.64.237.128/25 ip4:116.128.173.0/25 ip4:121.51.40.128/25 ip4:121.51.6.0/25 ip4:162.62.52.214 ip4:162.62.55.67 ip4:162.62.57.0/24 ip4:162.62.58.211 ip4:162.62.58.216 -all"
"v=spf1 ip4:162.62.58.69 ip4:162.62.63.194 ip4:180.163.24.128/25 ip4:183.2.187.0/25 ip4:203.205.221.128/25 ip4:203.205.251.0/25 ip4:210.51.43.0/25 ip4:58.246.222.128/25 ip4:58.250.143.128/25 ip4:61.241.55.128/25 -all"
"v=spf1 ip4:113.108.92.0/25 ip4:121.14.77.0/25 ip4:81.69.217.16/28 ip4:54.164.151.162 -all"
"v=spf1 ip4:114.132.122.39 ip4:114.132.123.192 ip4:114.132.124.171 ip4:114.132.125.233 ip4:114.132.197.227 ip4:114.132.224.180 ip4:114.132.233.22 ip4:114.132.58.0/24 ip4:43.155.65.254 ip4:114.132.62.0/24 ip4:106.55.200.77 -all"
"v=spf1 ip4:114.132.63.24 ip4:114.132.64.0/26 ip4:114.132.65.219 ip4:43.155.67.158 ip4:114.132.67.179 ip4:114.132.73.137 ip4:114.132.74.132 ip4:43.154.209.5 ip4:43.154.197.177 ip4:43.154.155.102 ip4:43.155.80.173 ip4:43.154.221.58 -all"
"v=spf1 ip4:54.204.34.129 ip4:54.204.34.130 ip4:54.243.244.52 ip4:52.205.10.60 ip4:35.173.142.173 ip4:54.207.22.56 ip4:54.207.19.206 ip4:54.254.200.92 ip4:54.254.200.128 ip4:54.92.39.34 ip4:54.206.16.166 ip4:54.206.34.216 ip4:114.132.75.215 -all"
"v=spf1 ip4:52.59.177.22 ip4:18.194.254.142 ip4:18.132.163.193 ip4:18.169.211.239 ip4:13.245.186.79 ip4:13.245.218.24 ip4:15.184.224.54 ip4:15.184.82.18 ip4:114.132.76.87 ip4:114.132.77.159 ip4:114.132.78.196 ip4:114.132.79.153 ip4:43.154.54.12 -all"
语法
-
"v=spf1":指定 SPF 记录的版本,目前只有 SPFv1 版本。
-
机制(Mechanisms):SPF 使用机制来指定哪些服务器被授权发送邮件。常用的机制有:
- "all":定义了所有情况下的默认结果。可以是 "+all"(通过验证)或 "-all"(不通过验证)。例如,"-all" 表示除非匹配其他通过机制,否则所有情况都不通过验证,即严格拒绝伪造邮件。
- "ip4" 和 "ip6":指定允许发送邮件的 IPv4 和 IPv6 地址。例如:"ip4:192.0.2.1" 表示允许来自 192.0.2.1 的服务器发送邮件。
- "a" 和 "mx":允许域名的 A 记录和 MX 记录指定的主机发送邮件。
- "include":允许引用其他域名的 SPF 记录。例如:"include:example.com" 表示允许按照 example.com 的 SPF 记录来验证。
-
修饰符(Modifiers):修饰符可以在机制之后指定,用于调整验证的结果。常用的修饰符有:
- "+":显示通过验证。
- "-":显示不通过验证,相当于 "-all"。
- "~":软失败,邮件可能被接受,但会标记为不可信。
- "?":中性结果,邮件可能被接受,但不影响验证的结果。
SPF 记录示例:
v=spf1 ip4:192.0.2.1 a mx ~all
以上示例表示允许 IP 地址为 192.0.2.1 的服务器、A 记录和 MX 记录指定的主机发送邮件,但验证结果为软失败,邮件可能会被接受,但标记为不可信。
DNS SPF 类型
IANA 设计了一种专门的 DNS 类型用来记录 SPF 信息,但是采用率非常低。
可以忽略,继续使用 TXT 类型来保存 SPF 信息。
参考资料与拓展阅读
- Sender Policy Framework
- RFC4408, Experimental / 2006, Sender Policy Framework (SPF) for Authorizing Use of Domains in E-Mail, Version 1
- RFC7208, Standards Track / 2014, Sender Policy Framework (SPF) for Authorizing Use of Domains in Email, Version 1
- http://www.open-spf.org/Tools/
-
Golang 库:https://github.com/mileusna/spf
package main
import (
"net"
"github.com/mileusna/spf"
)
func main() {
// optional, set DNS server which will be used by resolver.
// Default is Google's 8.8.8.8:53
spf.DNSServer = "1.1.1.1:53"
ip := net.ParseIP("123.123.123.123")
r := spf.CheckHost(ip, "domain.com", "name@domain.com", "");
// returns spf check result
// "PASS" / "FAIL" / "SOFTFAIL" / "NEUTRAL" / "NONE" / "TEMPERROR" / "PERMERROR"
// if you only need to retrive SPF record as string from DNS
spfRecord, _ := spf.LookupSPF("domain.com")
}
-
Golang 库:https://github.com/asggo/spf
package main
import "github.com/asggo/spf"
func main() {
SMTPClientIP := "1.1.1.1"
envelopeFrom := "info@example.com"
result, err := spf.SPFTest(SMTPClientIP, envelopeFrom)
if err != nil {
panic(err)
}
switch result {
case spf.Pass:
// allow action
case spf.Fail:
// deny action
}
//...
}
Email 信息安全
2020-02-10
DomainKeys Identified Mail,域名密钥识别邮件
作用是使用非对称加密(公钥 + 私钥)对邮件内容进行签名,防止伪造和篡改。
历史
- 2004 年,雅虎 DomainKeys 和思科 Identified Internet Mail 合并为 DKIM。
- 2007 年 2 月,DKIM 被列入互联网工程工作小组(IETF)的标准提案(Proposed Standard),并于同年 5 月成为正式标准(Standards Track)。
示例
DKIM-Signature: v=1; a=rsa-sha256; d=example.net; s=brisbane;
c=relaxed/simple; q=dns/txt; i=foo@eng.example.net;
t=1117574938; x=1118006938; l=200;
h=from:to:subject:date:keywords:keywords;
z=From:foo@eng.example.net|To:joe@example.com|
Subject:demo=20run|Date:July=205,=202005=203:44:08=20PM=20-0700;
bh=MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=;
b=dzdVyOfAKCdLXdJOc9G2q8LoXSlEniSbav+yuU4zGeeruD00lszZ
VoG4ZHRNiYzR
| Tag |
Required |
Meanning |
| v |
✓ |
version |
| a |
✓ |
signing algorithm |
| d |
✓ |
Signing Domain Identifier (SDID) |
| s |
✓ |
selector |
| c |
- |
canonicalization algorithm(s) for header and body |
| q |
- |
default query method |
| i |
- |
Agent or User Identifier (AUID) |
| t |
recommended |
signature timestamp |
| x |
recommended |
expire time |
| l |
- |
body length |
| h |
✓ |
header fields - list of those that have been signed |
| z |
- |
header fields - copy of selected header fields and values |
| bh |
✓ |
body hash |
| b |
✓ |
signature of headers and body |
示例 2
邮件中的 DKIM-Signature 头:
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=mail.instagram.com;
s=s1024-2013-q3; t=1674163477;
bh=6RXa/HYJQNKpB5PIGtLn7v1NE/4T5FaqxBLWNHVRZu8=;
h=Date:To:Subject:From:MIME-Version:Content-Type;
b=VAY3x16QtXeH1rQxu6eEbzhfgZl69m1sG9XzN3ym4FbWiMg+K+IfMGF4yszGYk8yO
YXAAJZuQfG45pjthISDDSwhhBK0WGgufQ8ofnzhNUN9WT/okEATC+JfzksS9w2Ts4V
ALa/4HHXnikQV5AFNJJNJIvWMN/fJ5c49nLkW024=
域名中的 DKIM 公钥:
dig TXT +short s1024-2013-q3._domainkey.mail.instagram.com
"k=rsa; t=s; h=sha256; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC7twdVo+BW8Pv2poU5129KYmE6npHdxUU8fktUKTE9TNovCvLy5LVjYc3TQcUFjOH" "VaZ89ZCjmpAcrA2QnTEKZ/2QWV56gn6bWdFW4SFxnQdHjguBZQykfKe5KTxy2a/OxuA0x2dHfdnYfw7RVzr4uednpKcWJy4Rl3gM6XB1zDwIDAQAB"
Python 编程中的应用
准备工作
- selector 选择 s2020 (随便)
- 生成密钥对
# 方法一:使用 OpenDKIM
sudo apt install -y opendkim-tools
opendkim-genkey --help
opendkim-genkey -D . -d markjour.com -s s2020
# 方法二:使用 OpenSSL
openssl genrsa -out dkim-markjour-s2020.pem 2048
openssl rsa -in dkim-markjour-s2020.pem -pubout -outform der 2>/dev/null | openssl base64 -A > dkim-markjour-s2020.pub
- 配置 DNS
s2020._domainkey.markjour.com
"v=DKIM1; h=sha256; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjnfmXLuyBt0Tus/Bdr87GpLqcRCZX7UC61OiPZ1Y3MG42qBcdEAMJfu7qop7KOLL8cywTRxiX39ehmf0ZovAXH1KkijiX/16tkI3cO9T6KS4vyr0Ip3fsGgNgjn5rH3M5AZAmbym6DIzYrtpTiAKgLYmFLALd9SLi/OhFIltWK+QJhaJgcuWUXCzlry01Fdsv1qj28WdZ6PQbQrSffc1qzkvOEOlmZXwWjQfg5X4E3DR4WKenC6f5WdcJeXk4pUeBOdQDoEM+4uCk4S6cN3OuYEQbvVmfQ5RAlCODccx7lJemWZZnlIf+03FppUEEMENZ8tu3iixD24m2q9wDLDL5QIDAQAB
v 版本,只有一种选择:DKIM1,必须放最前面,可以忽略
h 哈希算法,sha1 或者 sha256
k 密钥类型,只有一种选择:rsa,可以忽略
n 注释,可以忽略
p 公钥(ASN.1 DER-encoded + Base64)
s 服务类型,默认 *,表示所有服务,可以忽略
t 逗号隔开的标记
- y 测试
- s DKIM 签名中的 i= 域名必须是 d= 域名完全相同(子域也不行)。
参考:
签名
headers = {'aaa': '123', 'bbb': '456', 'ccc': '789'}
校验签名
mail = """
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qq.com; s=s0907;
t=1331524836; bh=Pqr4lbxMcef/3IqsXx/edT0iwPe18N7n8qKmQSnLio8=;
h=X-QQ-SSF:X-QQ-Spam:X-QQ-BUSINESS-ORIGIN:X-Originating-IP:
X-QQ-STYLE:X-QQ-mid:From:To:Sender:Subject:Mime-Version:
Content-Type:Content-Transfer-Encoding:Date:X-Priority:Message-ID:
X-QQ-MIME:X-Mailer:X-QQ-Mailer:X-QQ-ReplyHash;
b=hF3hXt429Mp9WUJx9wQQYYk32EABCQST/OmV+dI+vJ/XIidVkc6fsh8l/vBz/optb
MDp0XIupHHkUozz6jwMryhHd/ZNjLNtBBAIOgl1wH7R016x8uTtDQink5uIPH+5
X-QQ-SSF: 0000000000010060
X-QQ-Spam: true
X-QQ-BUSINESS-ORIGIN: 2
X-Originating-IP: 61.151.148.196
X-QQ-STYLE:
X-QQ-mid: bizmail6t1331524835t2734595
From: "=?gb18030?B?wffE6g==?=" <thinkphp@qq.com>
To: "=?gb18030?B?uvqwug==?=" <ninedoors@126.com>
Sender: liuchen@topthink.net
Subject: =?gb18030?B?UmU60rvOu1RQZXK1xNLJu/M=?=
Mime-Version: 1.0
Content-Type: multipart/alternative;
boundary="----=_NextPart_4F5D74E3_DF6406C0_249C5176"
Content-Transfer-Encoding: 8Bit
Date: Mon, 12 Mar 2012 12:00:35 +0800
X-Priority: 3
Message-ID: <tencent_519100472CAA258E750FA58D@qq.com>
X-QQ-MIME: TCMime 1.0 by Tencent
X-Mailer: QQMail 2.x
X-QQ-Mailer: QQMail 2.x
X-QQ-ReplyHash: 3949397671
""".strip('\n')
JOB
2020-02-09
职责
- On-call (电话值班)的计划或者规定是什么?值班或者遇到问题加班时候有加班费吗?
- 我的日常工作是什么?
- 有给我设定的特定目标吗?
- 团队里面初级和高级工程师的比例是多少?(有计划改变吗)
- 入职培训 (onboarding) 会是什么样的?
- 每个开发者有多大的自由来做出决定?
- 在你看来,这个工作做到什么程度算成功?
- 你期望我在最初的一个月 / 三个月能够完成什么?
- 试用期结束的时候,你会怎么样衡量我的绩效?
- 自己单独的开发活动和按部就班工作的比例大概是怎样的?
- 一个典型的一天或者一周的工作是怎样安排的?
- 对我的申请你有什么疑虑么?
- 在这份工作上,我将会和谁紧密合作?
- 我的直接上级他们的上级都是什么样的管理风格?(事无巨细还是着眼宏观)
- 我在这个岗位上应该如何发展?会有哪些机会?
- 每天预期 / 核心工作时间是多少小时?
- 我入职的岗位是新增还是接替之前离职的同事?(是否有技术债需要还)?(zh)
- 入职之后在哪个项目组,项目是新成立还是已有的?(zh)
技术
- 公司常用的技术栈是什么?
- 你们怎么使用源码控制系统?
- 你们怎么测试代码?
- 你们怎么追踪 bug?
- 你们怎样监控项目?
- 你们怎么集成和部署代码改动?是使用持续集成和持续部署吗 (CI/CD)?
- 你们的基础设施搭建在版本管理系统里吗?或者是代码化的吗?
- 从计划到完成一项任务的工作流是什么样的?
- 你们如何准备故障恢复?
- 有标准的开发环境吗?是强制的吗?
- 你们需要花费多长时间来给产品搭建一个本地测试环境?(分钟 / 小时 / 天)
- 你们需要花费多长时间来响应代码或者依赖中的安全问题?
- 所有的开发者都可以使用他们电脑的本地管理员权限吗?
- 介绍一下你们的技术原则或者展望。
- 你们的代码有开发文档吗?有没有单独的供消费者阅读的文档?
- 你们有更高层次的文档吗?比如说 ER 图,数据库范式
- 你们使用静态代码分析吗?
- 你们如何管理内部和外部的数字资产?
- 你们如何管理依赖?
- 公司是否有技术分享交流活动?有的话,多久一次呢?(zh)
- 你们的数据库是怎么进行版本控制的?(zh)
- 业务需求有没有文档记录?是如何记录的?(zh)
- 你们是如何面对和解决技术债的?是否有专门的时间或者预算用于重构?
- 你们如何进行单元测试呢,是否都有单元测试的习惯?
团队
- 工作是怎么组织的?
- 团队内 / 团队间的交流通常是怎样的?
- 你们使用什么工具来做项目组织?你的实际体会是什么?
- 如果遇到不同的意见怎样处理?
- 谁来设定优先级 / 计划?
- 如果团队没能赶上预期发布日期怎么办?
- 每周都会开什么类型的会议?
- 会有定期的和上级的一对一谈话吗?
- 产品 / 服务的规划是什么样的?(n 周一发布 / 持续部署 / 多个发布流 / ...)
- 生产环境发生事故了怎么办?是否有不批评人而分析问题的文化?
- 有没有一些团队正在经历还尚待解决的挑战?
- 你们如何跟踪进度?
- 预期和目标是如何设定的?谁来设定?
- Code Review 如何实施?
- 给我介绍下团队里一个典型的 sprint
- 你们如何平衡技术和商业目标?
- 你们如何共享知识?
- 团队有多大?
- 公司技术团队的架构和人员组成?(zh)
- 团队内开发、产品、运营哪一方是需求的主要提出方?哪一方更强势?(zh)
问未来的同事
- 开发者倾向于从哪里学习?
- 你对在这里工作最满意的地方是?
- 最不满意的呢?
- 如果可以的话,你想改变哪里?
- 团队最老的成员在这里多久了?
- 在小团队中,有没有出现成员性格互相冲突的情况?最后是如何解决的?
公司
- 公司为什么在招人?(产品发展 / 新产品 / 波动...)
- 有没有会议 / 旅行预算?使用的规定是什么?
- 晋升流程是怎样的?要求 / 预期是怎样沟通的?
- 绩效评估流程是怎样的?
- 技术和管理两条职业路径是分开的吗?
- 对于多元化招聘的现状或者观点是什么?
- 有公司级别的学习资源吗?比如电子书订阅或者在线课程?
- 有获取证书的预算吗?
- 公司的成熟度如何?(早期寻找方向 / 有内容的工作 / 维护中 / ...)
- 我可以为开源项目做贡献吗?是否需要审批?
- 你认为公司未来五年或者十年会发展成什么样子?
- 公司的大多数员工是如何看待整洁代码的?
- 你上次注意到有人成长是什么时候?他们在哪方面成长了?
- 在这里成功的定义是什么?如何衡量成功?
- 有体育活动或者团建么?
- 有内部的黑客马拉松活动吗?
- 公司支持开源项目吗?
- 有竞业限制或者保密协议需要签吗?
- 你们认为公司文化中的空白是什么?
- 能够跟我说一公司处于不良情况,以及如何处理的故事吗?
- 您在这工作了多久了?您觉得体验如何?(zh)
- 大家为什么会喜欢这里?(zh)
- 公司的调薪制度是如何的?(zh)
- 公司有没有申请调岗的制度?
- 公司对于员工的心理健康和福祉有什么具体措施?
- 你对在这里工作最满意的地方是?你为什么留在这家公司?
社会问题
- 你们关于多元化招聘什么看法?
- 你们的公司文化如何?你认为有什么空白么?
- 这里的工作生活平衡地怎么样?
- 公司对气候变化有什么态度吗?
冲突
- 不同的意见如何处理?
- 如果被退回了会怎样?(“这个在预计的时间内做不完”)
- 当团队有压力并且在超负荷工作的时候怎么处理?
- 如果有人注意到了在流程或者技术等其他方面又改进的地方,怎么办?
- 当管理层的预期和工程师的绩效之间有差距的时候如何处理?
- 能给我讲一个公司深处有毒环境以及如何处理的故事吗?
- 如果在公司内你的同事因涉嫌性侵犯他人而被调查,请问你会如何处理?
- 假设我自己很不幸是在公司内被性侵的受害者,在公司内部有没有争取合法权益的渠道?
商业
- 你们现在盈利吗?
- 如果没有的话,还需要多久?
- 如果有的话,年度营业额是大概有多少?(我现在的公司年度营业额是 5 亿)
- 公司的资金来源是什么?谁影响或者制定高层计划或方向?
- 你们如何挣钱?
- 什么阻止了你们挣更多的钱?
- 公司未来一年的增长计划怎样?五年呢?
- 你们认为什么是你们的竞争优势?
- 你们的竞争优势是什么?
- 公司未来的商业规划是怎样的?有上市的计划吗?(zh)
- 都在做副业吗?
远程工作
- 远程工作和办公室工作的比例是多少?
- 公司提供硬件吗?更新计划如何?
- 使用自己的硬件办公可以吗?现在有政策吗?
- 额外的附件和家具可以通过公司购买吗?这方面是否有预算?
- 有共享办公或者上网的预算吗?
- 多久需要去一次办公室?
- 公司的会议室是否一直是视频会议就绪的?
办公室布局
- 办公室的布局如何?(开放的 / 小隔间 / 独立办公室)
- 有没有支持 / 市场 / 或者其他需要大量打电话的团队在我的团队旁边办公?
终极问题
- 该职位为何会空缺?
- 公司如何保证人才不流失?
- 这份工作 / 团队 / 公司最好和最坏的方面是?
- 你最开始为什么选择了这家公司?
- 你为什么留在这家公司?
待遇
- 如果有奖金计划的话,奖金如何分配?
- 如果有奖金计划的话,过去的几年里通常会发百分之多少的奖金?
- 有五险一金(zh)/401k(us)或者其他退休养老金等福利吗?
- 五险一金中,补充公积金一般交多少比例?/401k 一般交多少比例?我可以自己选择这一比例吗?
- 有什么医疗保险吗?如果有的话何时开始?
- 有额外商业保险吗?例如人寿保险和额外的养老/医疗保险?
- 商业保险可以给家人办理吗?成年人/未成年人?
- 更换工作地点,公司付费吗?
- 是否可以申请更换工作地点?
- 是否愿意协助海外应聘者申请工作签证?
休假
- 带薪休假时间有多久?
- 病假和事假是分开的还是一起算?
- 我可以提前使用假期时间吗?也就是说应休假期是负的?
- 假期的更新策略是什么样的?也就是说未休的假期能否滚入下一周期
- 照顾小孩的政策如何?
- 无薪休假政策是什么样的?
- 学术性休假政策是怎么样的?
- 孕产假政策具体是怎样的?
福利
- 公司提供 mac 开发吗?
- 使用自带电脑有补贴吗?
- 公积金多少比例缴纳?
- 公司是否有食堂,是否有餐饮福利补贴?
- 是否提供租房补贴?
- 是否提供话费补贴?
- 是否有交通补贴?
人才培养
- 升职加薪条件是否量化?
- 每年给团队安排多少费用用于学习培训?
- 每年组织多少次关于技术能力提升的讲座/论坛?
软件设计
2020-02-08
:) 本文正在编辑中,暂时不提供浏览...
Python 加密
2020-02-05
和 PyCrypto 的关系
PyCrypto 是 Python 界最知名的加密模块,它提供了一系列的加密算法,包括对称加密、非对称加密、哈希算法、签名算法等。
不过有一个很大的问题:上一个版本 2.6.1 发布于 2013-10-18,已经很多年没有维护了。
PyCryptodome 是 PyCrypto 的分叉,该项目在统一套代码的基础上提供了两种包:pycryptodome 和 pycryptodomex:
- 前者保持对 PyCrypto 的兼容,所有的代码都在
Crypto 名称下,
-
后者丢掉了历史包袱,放弃对 PyCrypto 的兼容,所有代码都在 Cryptodome 名称下。
-
https://pypi.org/project/pycryptodome/
- https://pypi.org/project/pycryptodomex/
- https://www.pycryptodome.org/en/latest/
- https://github.com/Legrandin/pycryptodome/
其他加密模块
示例
云计算
2020-02-01
公有云 Public Cloud
云计算厂商提供的公共服务,比如腾讯云、阿里云等。
私有云 Private Cloud
个人和组织自己搭建的(可能是厂商帮忙搭建),自用的云计算服务。机器由个人或组织持有(可能在云计算厂商的机房中)。
优点是数据完全掌握在自己手中。如果规模没有达到一定程度的话,这样做的成本会比较高(除了固定资产的投入之外,维护成本不可忽视)。
有一种形式,是一些利益相关的个体,对计算有着相同或相似的需求,然后共同搭建一个云服务平台。
比如 XX 市弄一个政务云,下属政府机构直接使用这个云服务平台。
又比如某地教育单位弄一个云服务平台,下属学校有啥服务的话,就都使用这个云服务平台。
专有云
有些厂商提供 “专有云” 的服务:整套设施就为单个客户专门提供服务。设备属于厂商所有。
感觉这个算公有云,私有云的交叉地带,只好单独算一类。
知乎上看到一个比喻:公有云是小姐,私有云是老婆,专有云是小三 (包养)。比较贴切。
混合云 Hybrid Cloud
一般意义上,混合云是指公有云和私有云的结合。
PS: 多个私有云之间,或多个公有云之间,相互共享资源,也可以叫做混合云。
应该是通过一些对接好了各大厂商(比如腾讯云,阿里云)和常见私有云平台(比如 OpenStack,CloudStack)的管理工具,对所有资源进行整合管理。
也可能部分二次开发过的私有云平台支持对接公有云,可以直接调度和整合公有云资源。
开发者 ASN1 网络编程
2020-01-30
我印象中曾在某个项目中接触到了这种格式,但是一时间竟也想不起来。
PS: 可能是有一次涉及 LDAP 协议的时候。
概念
ASN 全名 Abstract Syntax Notation, 翻译过来就是:抽象语法标记。
ASN.1 可能是第一版的意思(?)。
asn.1 是一套国际标准,用来定义一种通用的、严谨的数据表示(标记)方法,以及对应的数据编码格式。
PS:对数据 Scheme 的定义独立于硬件架构和编程语言。
- ITU-T Rec. X.680 (2015) | ISO/IEC 8824-1:2015
Specification of basic notation
- ITU-T Rec. X.681 (2015) | ISO/IEC 8824-2:2015
Information object specification
- ITU-T Rec. X.682 (2015) | ISO/IEC 8824-3:2015
Constraint specification
- ITU-T Rec. X.683 (2015) | ISO/IEC 8824-4:2015
Parameterization of ASN.1 specifications
- ITU-T Rec. X.690 (2015) | ISO/IEC 8825-1:2015
BER, CER and DER
PS:常见证书格式 der 就是来自这个 DER。
- ITU-T Rec. X.691 (2015) | ISO/IEC 8825-2:2015
PER (Packed Encoding Rules)
- ITU-T Rec. X.692 (2015) | ISO/IEC 8825-3:2015
ECN (Extended Component Notation)
- ITU-T Rec. X.693 (2015) | ISO/IEC 8825-4:2015
XER (XML Encoding Rules)
- ITU-T Rec. X.694 (2015) | ISO/IEC 8825-5:2015
Mapping W3C XML schema definitions into ASN.1
- ITU-T Rec. X.695 (2015) | ISO/IEC 8825-6:2015
Registration and application of PER encoding instructions
- ITU-T Rec. X.696 (2015) | ISO/IEC 8825-7:2015
OER (Octet Encoding Rules)
- ITU-T Rec. X.697 (2017) | ISO/IEC 8825-8:2018
JER (JSON Encoding Rules)
一般又被称之为 X.680 系列,最早是 1995 年出第一版。最新的是 2018 年出的 5.4 版(X.680 (2015) Amd. 1)
PS:2021 年 X.680 出了第六版。
部分应用层的网络协议就使用了 ASN.1 格式,比如 X.500 Directory Services,LDAP,VoIP,PKCS,Kerberos,移动通信(2G/GSM,GRPS,一直到 5G)。
它和 JSON 这种通用数据交换格式完全不同,更加类似与 protobuf,msgpack,thrift 这样,提供一个完备的数据定义语法用来声明 Schema(ASN.1 称之为模块),然后基于二进制紧凑地表示数据。所以非常适合用在 C/S 架构的网络编程上,作为服务通讯协议的一部分,负责内外数据交换,也就是 TCP/UDP 服务的接口部分。
如果要将 ASN.1 归类的话,更贴切的应该是接口定义语言,或者叫协议定义语言。
要是了解到 ASN.1 出现的年份(1984)的话,对照它的竞争者出现的时间,会发现它的设计确实比较超前。不管怎么说,这些晚辈确实更加流行,作为国际标准的 ASN.1 不够卖座,肯定是也有不好的地方。
PS:可能是 ASN.1 历史包袱太重, 不够轻便 (我看到的一些评论和我的猜想比较符合)。
数据定义
先来一个示例(维基上找来的,感觉没啥意义):
FooProtocol DEFINITIONS ::= BEGIN
FooQuestion ::= SEQUENCE {
-- 跟踪编号,后面括号是限制值的范围
trackingNumber INTEGER(0..199),
-- 问题内容,字符串
question IA5String
}
FooAnswer ::= SEQUENCE {
-- 问题编号
questionNumber INTEGER(10..20),
-- 答案内容
answer BOOLEAN
}
FooHistory ::= SEQUENCE {
-- 问题数组
questions SEQUENCE(SIZE(0..10)) OF FooQuestion,
-- 答案数组
answers SEQUENCE(SIZE(1..10)) OF FooAnswer,
-- 一个整型数组
anArray SEQUENCE(SIZE(100)) OF INTEGER(0..1000),
...
}
END
基本语法
- 大小写字母,数字,短横杠,空格
标识符:小写字母开头
类型名称:大写字母开头
- 多个空白符号(空格、换行)会当作一个空格
- 数据类型都有一个 TagNumber
-- 注释
数据类型
简单类型
结构化类型
标记类型
其他类型:CHOICE,ANY
类别:
- 0 Universal 通用类型
- 1 Application 应用协议相关类型
- 2 Context-specific
- 3 Private 自定义
结构化:
原始类型:
| Type |
Tag number |
备注 |
INTEGER |
2 |
整型 |
BIT STRING |
3 |
|
OCTET STRING |
4 |
|
NULL |
5 |
NULL |
OBJECT IDENTIFIER |
6 |
对象 |
SEQUENCE and
SEQUENCE OF |
16 |
数组 |
SET and SET OF |
17 |
集合 |
PrintableString |
19 |
字符串 |
T61String |
20 |
|
IA5String |
22 |
|
UTCTime |
23 |
时间 |
示例:
编码规则
- 基本编码规则(BER,Basic Encoding Rules)
- 规范编码规则(CER,Canonical Encoding Rules)
- 唯一编码规则(DER,Distinguished Encoding Rules)
- 压缩编码规则(PER,Packed Encoding Rules)
- XML 编码规则(XER,XML Encoding Rules)
Python
https://www.cnblogs.com/20175211lyz/p/12769883.html
https://github.com/etingof/pyasn1
上面的示例通过 asn1ate /tmp/foo.asn > /tmp/foo.py 生成 Python 代码:
PS:并不是一定需要定义成这样类的结构,只是 pyasn1 库适合这样用而已。
from pyasn1.type import univ, char, namedtype, namedval, tag, constraint, useful
class FooAnswer(univ.Sequence):
pass
FooAnswer.componentType = namedtype.NamedTypes(
namedtype.NamedType('questionNumber', univ.Integer().subtype(subtypeSpec=constraint.ValueRangeConstraint(10, 20))),
namedtype.NamedType('answer', univ.Boolean())
)
class FooQuestion(univ.Sequence):
pass
FooQuestion.componentType = namedtype.NamedTypes(
namedtype.NamedType('trackingNumber', univ.Integer().subtype(subtypeSpec=constraint.ValueRangeConstraint(0, 199))),
namedtype.NamedType('question', char.IA5String())
)
class FooHistory(univ.Sequence):
pass
FooHistory.componentType = namedtype.NamedTypes(
namedtype.NamedType('questions', univ.SequenceOf(componentType=FooQuestion()).subtype(subtypeSpec=constraint.ValueSizeConstraint(0, 10))),
namedtype.NamedType('answers', univ.SequenceOf(componentType=FooAnswer()).subtype(subtypeSpec=constraint.ValueSizeConstraint(1, 10))),
namedtype.NamedType('anArray', univ.SequenceOf(componentType=univ.Integer().subtype(subtypeSpec=constraint.ValueRangeConstraint(0, 1000))).subtype(subtypeSpec=constraint.ValueSizeConstraint(100, 100)))
)
然后就可以使用了:
import foo
from pyasn1.codec.der.encoder import encode
fa = foo.FooAnswer()
fa['questionNumber'] = 10
fa['answer'] = False
fa_encoded = encode(fa)
print(fa_encoded) # b'0\x06\x02\x01\n\x01\x01\x00'
print(binascii.b2a_hex(fa_encoded).decode()) # 300602010a010100
from pyasn1.codec.der.decoder import decode
obj, rest = decode(fa_encoded)
print(obj)
# Sequence:
# field-0=10
# field-1=False
for k, v in obj.items():
print([k, v])
# ['field-0', <Integer value object, tagSet <TagSet object, tags 0:0:2>, payload [10]>]
# ['field-1', <Boolean value object, tagSet <TagSet object, tags 0:0:1>, subtypeSpec <ConstraintsIntersection object, consts <SingleValueConstraint object, consts 0, 1>>, namedValues <NamedValues object, enums False=0, True=1>, payload [False]>]
obj, rest = decode(fa_encoded, asn1Spec=foo.FooAnswer())
print(obj)
# FooAnswer:
# questionNumber=10
# answer=False
# print(dict(obj.items()))
print(dict([(k, str(v)) for k, v in obj.items()]))
# {'questionNumber': '10', 'answer': 'False'}
print(obj['questionNumber'].__dict__)
print(obj['questionNumber']._value) # 10
print(obj['answer'].__dict__)
print(obj['answer']._value) # 0
print([int(obj['questionNumber']), bool(obj['answer'])])
GitHub 找到的几个相关库:
- wbond/asn1crypto
Python ASN.1 library with a focus on performance and a pythonic API
- etingof/pyasn1
Generic ASN.1 library for Python
- eerimoq/asn1tools
ASN.1 parsing, encoding and decoding.
- P1sec/pycrate
A Python library to ease the development of encoders and decoders for various protocols and file formats; contains ASN.1
参考资料与拓展阅读
时事 COVID19
2020-01-29
具体的情况,网上不要太多,我说说我的经历和想法。
MySQL
2020-01-25
输入 help 之后,按照提示就会发现 MySQL 有一个主题树。
从头 help contents 开始:
Account Management
ALTER RESOURCE GROUP
ALTER USER
CREATE RESOURCE GROUP
CREATE ROLE
CREATE USER
DROP RESOURCE GROUP
DROP ROLE
DROP USER
GRANT
RENAME USER
REVOKE
SET DEFAULT ROLE
SET PASSWORD
SET RESOURCE GROUP
SET ROLE
Administration
BINLOG
CACHE INDEX
FLUSH
HELP COMMAND
KILL
LOAD INDEX
RESET
RESET PERSIST
RESTART
SET
SET CHARACTER SET
SET CHARSET
SET NAMES
SHOW
SHOW BINARY LOGS
SHOW BINLOG EVENTS
SHOW CHARACTER SET
SHOW COLLATION
SHOW COLUMNS
SHOW CREATE DATABASE
SHOW CREATE EVENT
SHOW CREATE FUNCTION
SHOW CREATE PROCEDURE
SHOW CREATE SCHEMA
SHOW CREATE TABLE
SHOW CREATE TRIGGER
SHOW CREATE USER
SHOW CREATE VIEW
SHOW DATABASES
SHOW ENGINE
SHOW ENGINES
SHOW ERRORS
SHOW EVENTS
SHOW FIELDS
SHOW FUNCTION CODE
SHOW FUNCTION STATUS
SHOW GRANTS
SHOW INDEX
SHOW MASTER LOGS
SHOW MASTER STATUS
SHOW OPEN TABLES
SHOW PLUGINS
SHOW PRIVILEGES
SHOW PROCEDURE CODE
SHOW PROCEDURE STATUS
SHOW PROCESSLIST
SHOW PROFILE
SHOW PROFILES
SHOW RELAYLOG EVENTS
SHOW REPLICA STATUS
SHOW REPLICAS
SHOW SCHEMAS
SHOW SLAVE HOSTS
SHOW SLAVE STATUS
SHOW STATUS
SHOW TABLE STATUS
SHOW TABLES
SHOW TRIGGERS
SHOW VARIABLES
SHOW WARNINGS
SHUTDOWN
Components
CLONE
INSTALL COMPONENT
UNINSTALL COMPONENT
UNINSTALL PLUGIN
Compound Statements
BEGIN END
CASE STATEMENT
CLOSE
DECLARE CONDITION
DECLARE CURSOR
DECLARE HANDLER
DECLARE VARIABLE
FETCH
GET DIAGNOSTICS
IF STATEMENT
ITERATE
LABELS
LEAVE
LOOP
OPEN
REPEAT LOOP
RESIGNAL
RETURN
SIGNAL
WHILE
Contents
Data Definition
ALTER DATABASE
ALTER EVENT
ALTER FUNCTION
ALTER INSTANCE
ALTER LOGFILE GROUP
ALTER PROCEDURE
ALTER SCHEMA
ALTER SERVER
ALTER TABLE
ALTER TABLESPACE
ALTER VIEW
CREATE DATABASE
CREATE EVENT
CREATE FUNCTION
CREATE INDEX
CREATE LOGFILE GROUP
CREATE PROCEDURE
CREATE SCHEMA
CREATE SERVER
CREATE SPATIAL REFERENCE SYSTEM
CREATE TABLE
CREATE TABLESPACE
CREATE TRIGGER
CREATE VIEW
DROP DATABASE
DROP EVENT
DROP FUNCTION
DROP INDEX
DROP PROCEDURE
DROP SCHEMA
DROP SERVER
DROP SPATIAL REFERENCE SYSTEM
DROP TABLE
DROP TABLESPACE
DROP TRIGGER
DROP VIEW
FOREIGN KEY
RENAME TABLE
TRUNCATE TABLE
Data Manipulation
CALL
DELETE
DO
DUAL
HANDLER
IMPORT TABLE
INSERT
INSERT DELAYED
INSERT SELECT
JOIN
LOAD DATA
LOAD XML
PARENTHESIZED QUERY EXPRESSIONS
REPLACE
SELECT
TABLE
UNION
UPDATE
VALUES STATEMENT
Data Types
AUTO_INCREMENT
BIGINT
BINARY
BIT
BLOB
BLOB DATA TYPE
BOOLEAN
CHAR
CHAR BYTE
DATE
DATETIME
DEC
DECIMAL
DOUBLE
DOUBLE PRECISION
ENUM
FLOAT
INT
INTEGER
LONGBLOB
LONGTEXT
MEDIUMBLOB
MEDIUMINT
MEDIUMTEXT
SET DATA TYPE
SMALLINT
TEXT
TIME
TIMESTAMP
TINYBLOB
TINYINT
TINYTEXT
VARBINARY
VARCHAR
YEAR DATA TYPE
Functions
Aggregate Functions and Modifiers
AVG
BIT_AND
BIT_OR
BIT_XOR
COUNT
COUNT DISTINCT
GROUP_CONCAT
JSON_ARRAYAGG
JSON_OBJECTAGG
MAX
MIN
STD
STDDEV
STDDEV_POP
STDDEV_SAMP
SUM
VARIANCE
VAR_POP
VAR_SAMP
Bit Functions
Cast Functions and Operators
BINARY OPERATOR
CAST
CONVERT
Comparison Operators
!=
<
<=
<=>
=
>
>=
BETWEEN AND
COALESCE
GREATEST
IN
INTERVAL
IS
IS NOT
IS NOT NULL
IS NULL
ISNULL
LEAST
NOT BETWEEN
NOT IN
Date and Time Functions
ADDDATE
ADDTIME
CONVERT_TZ
CURDATE
CURRENT_DATE
CURRENT_TIME
CURRENT_TIMESTAMP
CURTIME
DATE FUNCTION
DATEDIFF
DATE_ADD
DATE_FORMAT
DATE_SUB
DAY
DAYNAME
DAYOFMONTH
DAYOFWEEK
DAYOFYEAR
EXTRACT
FROM_DAYS
FROM_UNIXTIME
GET_FORMAT
HOUR
LAST_DAY
LOCALTIME
LOCALTIMESTAMP
MAKEDATE
MAKETIME
MICROSECOND
MINUTE
MONTH
MONTHNAME
NOW
PERIOD_ADD
PERIOD_DIFF
QUARTER
SECOND
SEC_TO_TIME
STR_TO_DATE
SUBDATE
SUBTIME
SYSDATE
TIME FUNCTION
TIMEDIFF
TIMESTAMP FUNCTION
TIMESTAMPADD
TIMESTAMPDIFF
TIME_FORMAT
TIME_TO_SEC
TO_DAYS
TO_SECONDS
UNIX_TIMESTAMP
UTC_DATE
UTC_TIME
UTC_TIMESTAMP
WEEK
WEEKDAY
WEEKOFYEAR
YEAR
YEARWEEK
Encryption Functions
AES_DECRYPT
AES_ENCRYPT
COMPRESS
MD5
RANDOM_BYTES
SHA1
SHA2
STATEMENT_DIGEST
STATEMENT_DIGEST_TEXT
UNCOMPRESS
UNCOMPRESSED_LENGTH
VALIDATE_PASSWORD_STRENGTH
Enterprise Encryption Functions
ASYMMETRIC_DECRYPT
ASYMMETRIC_DERIVE
ASYMMETRIC_ENCRYPT
ASYMMETRIC_SIGN
ASYMMETRIC_VERIFY
CREATE_ASYMMETRIC_PRIV_KEY
CREATE_ASYMMETRIC_PUB_KEY
CREATE_DH_PARAMETERS
CREATE_DIGEST
Flow Control Functions
CASE OPERATOR
IF FUNCTION
IFNULL
NULLIF
GROUP BY Functions and Modifiers
GTID
GTID_SUBSET
GTID_SUBTRACT
WAIT_FOR_EXECUTED_GTID_SET
WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS
Information Functions
BENCHMARK
CHARSET
COERCIBILITY
COLLATION
CONNECTION_ID
CURRENT_ROLE
CURRENT_USER
DATABASE
FOUND_ROWS
ICU_VERSION
LAST_INSERT_ID
ROLES_GRAPHML
ROW_COUNT
SCHEMA
SESSION_USER
SYSTEM_USER
USER
VERSION
Internal Functions
CAN_ACCESS_COLUMN
CAN_ACCESS_DATABASE
CAN_ACCESS_TABLE
CAN_ACCESS_USER
CAN_ACCESS_VIEW
GET_DD_COLUMN_PRIVILEGES
GET_DD_CREATE_OPTIONS
GET_DD_INDEX_SUB_PART_LENGTH
INTERNAL_AUTO_INCREMENT
INTERNAL_AVG_ROW_LENGTH
INTERNAL_CHECKSUM
INTERNAL_CHECK_TIME
INTERNAL_DATA_FREE
INTERNAL_DATA_LENGTH
INTERNAL_DD_CHAR_LENGTH
INTERNAL_GET_COMMENT_OR_ERROR
INTERNAL_GET_ENABLED_ROLE_JSON
INTERNAL_GET_HOSTNAME
INTERNAL_GET_USERNAME
INTERNAL_GET_VIEW_WARNING_OR_ERROR
INTERNAL_INDEX_COLUMN_CARDINALITY
INTERNAL_INDEX_LENGTH
INTERNAL_IS_ENABLED_ROLE
INTERNAL_IS_MANDATORY_ROLE
INTERNAL_KEYS_DISABLED
INTERNAL_MAX_DATA_LENGTH
INTERNAL_TABLE_ROWS
INTERNAL_UPDATE_TIME
IS_VISIBLE_DD_OBJECT
Locking Functions
GET_LOCK
IS_FREE_LOCK
IS_USED_LOCK
RELEASE_ALL_LOCKS
RELEASE_LOCK
Logical Operators
!
AND
ASSIGN-EQUAL
ASSIGN-VALUE
OR
XOR
Miscellaneous Functions
ANY_VALUE
BIN_TO_UUID
DEFAULT
GROUPING
INET6_ATON
INET6_NTOA
INET_ATON
INET_NTOA
IS_IPV4
IS_IPV4_COMPAT
IS_IPV4_MAPPED
IS_IPV6
IS_UUID
MASTER_POS_WAIT
NAME_CONST
SLEEP
SOURCE_POS_WAIT
UUID
UUID_SHORT
UUID_TO_BIN
VALUES
Numeric Functions
%
*
+
- BINARY
- UNARY
/
ABS
ACOS
ASIN
ATAN
ATAN2
CEIL
CEILING
CONV
COS
COT
CRC32
DEGREES
DIV
EXP
FLOOR
LN
LOG
LOG10
LOG2
MOD
PI
POW
POWER
RADIANS
RAND
ROUND
SIGN
SIN
SQRT
TAN
TRUNCATE
Performance Schema Functions
FORMAT_BYTES
FORMAT_PICO_TIME
PS_CURRENT_THREAD_ID
PS_THREAD_ID
Spatial Functions
Geometry Constructors
GEOMCOLLECTION
GEOMETRYCOLLECTION
LINESTRING
MULTILINESTRING
MULTIPOINT
MULTIPOLYGON
POINT
POLYGON
Geometry Property Functions
ST_DIMENSION
ST_ENVELOPE
ST_GEOMETRYTYPE
ST_ISEMPTY
ST_ISSIMPLE
ST_SRID
Geometry Relation Functions
ST_CONTAINS
ST_CROSSES
ST_DISJOINT
ST_DISTANCE
ST_EQUALS
ST_FRECHETDISTANCE
ST_HAUSDORFFDISTANCE
ST_INTERSECTS
ST_OVERLAPS
ST_TOUCHES
ST_WITHIN
GeometryCollection Property Functions
ST_BUFFER
ST_BUFFER_STRATEGY
ST_CONVEXHULL
ST_DIFFERENCE
ST_GEOMETRYN
ST_INTERSECTION
ST_LINEINTERPOLATEPOINT
ST_LINEINTERPOLATEPOINTS
ST_NUMGEOMETRIES
ST_POINTATDISTANCE
ST_SYMDIFFERENCE
ST_TRANSFORM
ST_UNION
LineString Property Functions
ST_ENDPOINT
ST_ISCLOSED
ST_LENGTH
ST_NUMPOINTS
ST_POINTN
ST_STARTPOINT
MBR Functions
->
->>
JSON_ARRAY
JSON_ARRAY_APPEND
JSON_ARRAY_INSERT
JSON_CONTAINS
JSON_CONTAINS_PATH
JSON_DEPTH
JSON_EXTRACT
JSON_INSERT
JSON_KEYS
JSON_LENGTH
JSON_MERGE
JSON_MERGE_PATCH()
JSON_MERGE_PRESERVE()
JSON_OBJECT
JSON_OVERLAPS
JSON_PRETTY
JSON_QUOTE
JSON_REMOVE
JSON_REPLACE
JSON_SCHEMA_VALID
JSON_SCHEMA_VALIDATION_REPORT
JSON_SEARCH
JSON_SET
JSON_STORAGE_FREE
JSON_STORAGE_SIZE
JSON_TABLE
JSON_TYPE
JSON_UNQUOTE
JSON_VALID
JSON_VALUE
MBRCONTAINS
MBRCOVEREDBY
MBRCOVERS
MBRDISJOINT
MBREQUALS
MBRINTERSECTS
MBROVERLAPS
MBRTOUCHES
MBRWITHIN
MEMBER OF
ST_ASGEOJSON
ST_COLLECT
ST_DISTANCE_SPHERE
ST_GEOHASH
ST_GEOMFROMGEOJSON
ST_ISVALID
ST_LATFROMGEOHASH
ST_LONGFROMGEOHASH
ST_MAKEENVELOPE
ST_POINTFROMGEOHASH
ST_SIMPLIFY
ST_VALIDATE
Point Property Functions
ST_LATITUDE
ST_LONGITUDE
ST_X
ST_Y
Polygon Property Functions
ST_AREA
ST_CENTROID
ST_EXTERIORRING
ST_INTERIORRINGN
ST_NUMINTERIORRINGS
WKB Functions
ST_ASBINARY
ST_ASTEXT
ST_GEOMCOLLFROMWKB
ST_GEOMFROMWKB
ST_LINEFROMWKB
ST_MLINEFROMWKB
ST_MPOINTFROMWKB
ST_MPOLYFROMWKB
ST_POINTFROMWKB
ST_POLYFROMWKB
ST_SWAPXY
WKT Functions
ST_GEOMCOLLFROMTEXT
ST_GEOMFROMTEXT
ST_LINEFROMTEXT
ST_MLINEFROMTEXT
ST_MPOINTFROMTEXT
ST_MPOLYFROMTEXT
ST_POINTFROMTEXT
ST_POLYFROMTEXT
String Functions
ASCII
BIN
BIT_LENGTH
CHAR FUNCTION
CHARACTER_LENGTH
CHAR_LENGTH
CONCAT
CONCAT_WS
ELT
EXPORT_SET
FIELD
FIND_IN_SET
FORMAT
FROM_BASE64
HEX
INSERT FUNCTION
INSTR
LCASE
LEFT
LENGTH
LIKE
LOAD_FILE
LOCATE
LOWER
LPAD
LTRIM
MAKE_SET
MATCH AGAINST
MID
NOT LIKE
NOT REGEXP
OCT
OCTET_LENGTH
ORD
POSITION
QUOTE
REGEXP
REGEXP_INSTR
REGEXP_LIKE
REGEXP_REPLACE
REGEXP_SUBSTR
REPEAT FUNCTION
REPLACE FUNCTION
REVERSE
RIGHT
RPAD
RTRIM
SOUNDEX
SOUNDS LIKE
SPACE
STRCMP
SUBSTR
SUBSTRING
SUBSTRING_INDEX
TO_BASE64
TRIM
UCASE
UNHEX
UPPER
WEIGHT_STRING
Window Functions
CUME_DIST
DENSE_RANK
FIRST_VALUE
LAG
LAST_VALUE
LEAD
NTH_VALUE
NTILE
PERCENT_RANK
RANK
ROW_NUMBER
XML
Geographic Features
GEOMETRY HIERARCHY
SPATIAL COLUMNS
SPATIAL INDEXES
MBR
WKT
Help Metadata
HELP_DATE
HELP_VERSION
Language Structure
FALSE
TRUE
Loadable Functions
CREATE FUNCTION LOADABLE FUNCTION
DROP FUNCTION LOADABLE FUNCTION
Plugins
Prepared Statements
DEALLOCATE PREPARE
DROP PREPARE
EXECUTE STATEMENT
PREPARE
Replication Statements
CHANGE MASTER TO
CHANGE REPLICATION FILTER
CHANGE REPLICATION SOURCE TO
PURGE BINARY LOGS
PURGE MASTER LOGS
RESET MASTER
RESET REPLICA
RESET SLAVE
SET SQL_LOG_BIN
START REPLICA
START SLAVE
STOP REPLICA
STOP SLAVE
Storage Engines
Table Maintenance
ANALYZE TABLE
CHECK TABLE
CHECKSUM TABLE
OPTIMIZE TABLE
REPAIR TABLE
Transactions
BEGIN
COMMIT
LOCK INSTANCE FOR BACKUP
LOCK TABLES
RELEASE SAVEPOINT
ROLLBACK
ROLLBACK TO SAVEPOINT
SAVEPOINT
SET TRANSACTION
START TRANSACTION
XA
Utility
DESC
DESCRIBE
EXPLAIN
HELP STATEMENT
USE
MySQL
2020-01-18
多线程执行 MySQL 查询的时候会遇到 Packet sequence number wrong 错误。
Traceback (most recent call last):
File "/tmp/db.py", line 167, in _execute
rowcount = cur.execute(sql, args)
File "/usr/local/lib/python2.7/site-packages/pymysql/cursors.py", line 163, in execute
result = self._query(query)
File "/usr/local/lib/python2.7/site-packages/pymysql/cursors.py", line 321, in _query
conn.query(q)
File "/usr/local/lib/python2.7/site-packages/pymysql/connections.py", line 505, in query
self._affected_rows = self._read_query_result(unbuffered=unbuffered)
File "/usr/local/lib/python2.7/site-packages/pymysql/connections.py", line 724, in _read_query_result
result.read()
File "/usr/local/lib/python2.7/site-packages/pymysql/connections.py", line 1076, in read
self._read_result_packet(first_packet)
File "/usr/local/lib/python2.7/site-packages/pymysql/connections.py", line 1146, in _read_result_packet
self._read_rowdata_packet()
File "/usr/local/lib/python2.7/site-packages/pymysql/connections.py", line 1180, in _read_rowdata_packet
packet = self.connection._read_packet()
File "/usr/local/lib/python2.7/site-packages/pymysql/connections.py", line 660, in _read_packet
% (packet_number, self._next_seq_id))
InternalError: Packet sequence number wrong - got 51 expected 178
多个查询共用连接,并发查询的时候,现在的 MySQL 网络传输机制无法判断这个返回属于哪个查询。
所以每个线程应该使用不同的连接,或者在 execute 之前加一个锁。