Python 设计模式
2015-04-06
使用全局变量
我个人比较喜欢的方式,简单高效。
class Application:
pass
APP = Application()
装饰器(使用特定方法来获取对象实例)
import threading
class singleton:
_instance_lock = threading.Lock()
def __init__(self, decorated):
self._decorated = decorated
def instance(self):
if not hasattr(self, '_instance'):
with singleton._instance_lock:
if not hasattr(self, '_instance'):
self._instance = self._decorated()
return self._instance
def __call__(self):
raise TypeError('Singletons must be accessed through `instance()`.')
def __instancecheck__(self, inst):
return isinstance(inst, self._decorated)
def __getattr__(self, name):
if name == '_instance':
raise AttributeError("'singleton' object has no attribute '_instance'")
return getattr(self.instance(), name)
@singleton
class Application:
pass
Application.instance()
装饰器
def singleton(cls):
_instances = {}
def _inner(*args, **kargs):
if cls not in _instances:
_instances[cls] = cls(*args, **kargs)
return _instances[cls]
return _inner
元类
class Application:
_instance_lock = threading.Lock()
def __new__(cls, *args, **kwargs):
if not hasattr(cls, "_instance"):
with cls._instance_lock:
if not hasattr(cls, "_instance"):
cls._instance = object.__new__(cls)
return cls._instance
改成通用方式:
import threading
class SingletonMeta(type):
_instances = {}
_instance_lock = threading.Lock()
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
with cls._instance_lock:
if cls not in cls._instances:
instance = super().__call__(*args, **kwargs)
cls._instances[cls] = instance
return cls._instances[cls]
class Application(metaclass=SingletonMeta):
pass
Django 密码学 加密 PBKDF2
2015-04-06
实现
在 Python 2.7.8 (July 2, 2014),或 Python 3.4 (March 17, 2014) 以上版本,标准库 hashlib 有 pbkdf2_hmac
:
import base64
import hashlib
import random
import secrets
def pbkdf2(password, salt, iterations, dklen=0, digest=None):
if digest is None:
digest = hashlib.sha256
if not dklen:
dklen = None
password = password.encode('utf-8')
salt = salt.encode('utf-8')
return hashlib.pbkdf2_hmac(
digest().name, password, salt, iterations, dklen)
### pbkdf2_sha256 ###
ALGORITHM = 'pbkdf2_sha256'
ITERATIONS = 30000
DIGEST = hashlib.sha256
def encode(password, salt, iterations=None):
assert password is not None
assert salt and '$' not in salt
if not iterations:
iterations = ITERATIONS
hash = pbkdf2(password, salt, iterations, digest=DIGEST)
hash = base64.b64encode(hash).decode('ascii').strip()
return "%s$%d$%s$%s" % (ALGORITHM, iterations, salt, hash)
def decode(encoded):
algorithm, iterations, salt, hash = encoded.split('$', 3)
assert algorithm == ALGORITHM
return {
'algorithm': algorithm,
'hash': hash,
'iterations': int(iterations),
'salt': salt,
}
def verify(password, encoded):
algorithm, iterations, salt, hash = encoded.split('$', 3)
assert algorithm == ALGORITHM
encoded_2 = encode(password, salt, int(iterations))
return secrets.compare_digest(encoded.encode('utf-8'),
encoded_2.encode('utf-8'))
salt_length = 32
# salt = bytes([random.randint(0, 255) for i in range(salt_length + 20)])
salt = random.randbytes(salt_length + 20)
salt = salt.replace(b'$', b'').decode('latin')[:salt_length]
# print(repr(salt))
a = encode('123456', salt)
print(repr(a))
print(decode(a))
# 'pbkdf2_sha256$30000$x\x82¨\x07Ó[Ám¬9V¬\x13·sÉ\x1eEܱ3\x04Ü\x07\x05BÁfM\x9fV×$/jqvasjfZX6c9xCytBVqddAJFve2DXcLWClTAsZvl48='
print(verify('234567', a))
print(verify('123456', a))
参考资料与拓展阅读
DB SQL MySQL
2015-03-22

Django 信息安全 密码学
2015-02-05
https://docs.djangoproject.com/en/2.0/topics/auth/passwords/
在 Django 中,密码哈希存储在 auth_user 表中的 password 字段中。该字段的值包含了算法名称、迭代次数、盐值和哈希值,它们都是使用特定的格式进行编码的。例如,一个密码哈希的值可能如下所示:
pbkdf2_sha256$150000$V7v0fjbhMIhq$Gd/0XuOqK3ib6NBNGVwIKGXcFTUiNbTzdTNN8RiW24E=
用美元符号切割,得到 4 部分:
pbkdf2_sha256
算法名称
150000
迭代次数
V7v0fjbhMIhq
盐
Gd/0XuOqK3ib6NBNGVwIKGXcFTUiNbTzdTNN8RiW24E=
支持的哈希算法
PASSWORD_HASHERS = [
'django.contrib.auth.hashers.PBKDF2PasswordHasher',
'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
'django.contrib.auth.hashers.Argon2PasswordHasher',
'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',
'django.contrib.auth.hashers.BCryptPasswordHasher',
]
默认使用的是 PBKDF2PasswordHasher
:
PBKDF2 是基于密钥的密码派生函数,它使用一个伪随机函数(PRF)和一个盐值来从给定密码派生出一个密钥。
PBKDF2 算法的核心是迭代的使用 PRF 函数,将每一次迭代的输出与前一次迭代的输出进行异或,生成最终的派生密钥。
大概逻辑如下:
import hashlib
import binascii
import os
class PBKDF2PasswordHasher:
algorithm = 'pbkdf2_sha256'
iterations = 100000
def salt(self):
return binascii.hexlify(os.urandom(16)).decode()
def encode(self, password, salt):
dk = hashlib.pbkdf2_hmac('sha256', password.encode(), salt.encode(), self.iterations)
return '%d$%s$%s' % (self.iterations, salt, binascii.hexlify(dk).decode())
def verify(self, password, encoded):
iterations, salt, dk = encoded.split('$')
iterations = int(iterations)
hashed_password = self.encode(password, salt)
return hashed_password == encoded
生成密码
from django.contrib.auth.hashers import make_password
password = '123456'
hashed_password = make_password(password)
验证密码
from django.contrib.auth.hashers import check_password
is_correct_password = check_password(password, hashed_password)
Web JavaScript
2015-01-30
Linux 压缩 zip unzip
2015-01-19
zip -e archive.zip file1.txt file2.txt
unzip -l archive.zip # 列出
# 解压缩
unzip archive.zip
unzip -o archive.zip # 覆盖
unzip archive.zip file1.txt file2.txt -d /path/to/directory/ # 指定文件,指定目录
unzip -P password archive.zip # 有密码的压缩文件
Linux
2015-01-17
信号
信号可以被捕获,或者被忽略,除了 9 KILL 和 19 STOP。
信号值
Ubuntu:
$ kill -l
HUP INT QUIT ILL TRAP IOT BUS FPE KILL USR1 SEGV USR2 PIPE ALRM TERM STKFLT CHLD CONT STOP TSTP TTIN TTOU URG XCPU XFSZ VTALRM PROF WINCH POLL PWR SYS
$ type kill
kill is a shell builtin
$ /usr/bin/kill -L
1 HUP 2 INT 3 QUIT 4 ILL 5 TRAP 6 ABRT 7 BUS
8 FPE 9 KILL 10 USR1 11 SEGV 12 USR2 13 PIPE 14 ALRM
15 TERM 16 STKFLT 17 CHLD 18 CONT 19 STOP 20 TSTP 21 TTIN
22 TTOU 23 URG 24 XCPU 25 XFSZ 26 VTALRM 27 PROF 28 WINCH
29 POLL 30 PWR 31 SYS
CentOS:
$ kill -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX
HUP
终端关闭
INT
Ctrl + C
QUIT
终端退出 Ctrl + 4 or \
ILL
TRAP
IOT
/ABRT
BUS
FPE
KILL
常来自 kill -9
USR1
SEGV
USR2
PIPE
ALRM
TERM
STKFLT
CHLD
子进程终止
CONT
STOP
TSTP
终端挂起 Ctrl + Z
TTIN
TTOU
URG
XCPU
XFSZ
VTALRM
PROF
WINCH
终端窗口大小改变
POLL
PWR
SYS
由于 9 KILL 不能被捕获,设计软件时可以捕获 15 TERM, 进行清理操作,然后需要杀进程时,先尝试 kill -15
。
附: 信号表(来自 man 7 signal
)
Signal |
x86/ARM most others |
Alpha/ SPARC |
MIPS |
PARISC |
Notes |
SIGHUP |
1 |
1 |
1 |
1 |
|
SIGINT |
2 |
2 |
2 |
2 |
|
SIGQUIT |
3 |
3 |
3 |
3 |
|
SIGILL |
4 |
4 |
4 |
4 |
|
SIGTRAP |
5 |
5 |
5 |
5 |
|
SIGABRT |
6 |
6 |
6 |
6 |
|
SIGIOT |
6 |
6 |
6 |
6 |
|
SIGBUS |
7 |
10 |
10 |
10 |
|
SIGEMT |
- |
7 |
7 |
- |
|
SIGFPE |
8 |
8 |
8 |
8 |
|
SIGKILL |
9 |
9 |
9 |
9 |
|
SIGUSR1 |
10 |
30 |
16 |
16 |
|
SIGSEGV |
11 |
11 |
11 |
11 |
|
SIGUSR2 |
12 |
31 |
17 |
17 |
|
SIGPIPE |
13 |
13 |
13 |
13 |
|
SIGALRM |
14 |
14 |
14 |
14 |
|
SIGTERM |
15 |
15 |
15 |
15 |
|
SIGSTKFLT |
16 |
- |
- |
7 |
|
SIGCHLD |
17 |
20 |
18 |
18 |
|
SIGCLD |
- |
- |
18 |
- |
|
SIGCONT |
18 |
19 |
25 |
26 |
|
SIGSTOP |
19 |
17 |
23 |
24 |
|
SIGTSTP |
20 |
18 |
24 |
25 |
|
SIGTTIN |
21 |
21 |
26 |
27 |
|
SIGTTOU |
22 |
22 |
27 |
28 |
|
SIGURG |
23 |
16 |
21 |
29 |
|
SIGXCPU |
24 |
24 |
30 |
12 |
|
SIGXFSZ |
25 |
25 |
31 |
30 |
|
SIGVTALRM |
26 |
26 |
28 |
20 |
|
SIGPROF |
27 |
27 |
29 |
21 |
|
SIGWINCH |
28 |
28 |
20 |
23 |
|
SIGIO |
29 |
23 |
22 |
22 |
|
SIGPOLL |
|
|
|
|
Same as SIGIO |
SIGPWR |
30 |
29/- |
19 |
19 |
|
SIGINFO |
- |
29/- |
- |
- |
|
SIGLOST |
- |
-/29 |
- |
- |
|
SIGSYS |
31 |
12 |
12 |
31 |
|
SIGUNUSED |
31 |
- |
- |
31 |
|
WebDev Apache
2015-01-04
2.2 版本下的权限控制语句在 2.4 下已经不再适用,需要做一些调整。
Order deny,allow
Deny from all
应该改成:Require all denied
Order deny,allow
Deny from all
Allow from example.com
应该改成:Require host example.com
Order allow,deny
Allow from all
应该改成:Require all granted
嗯,挺好,新语法更加简单。
Linux
2015-01-03
Linux 文件的三种时间:
atime
访问时间 Access
ctime
修改时间 Change, 文件状态变化
mtime
修改时间 Modify, 文件内容变化
注意:如果 chmod,chown,mv 等不改变文件内容的操作,ctime 变化,mtime 不变。
但是文件内容变化的时候,ctime 和 mtime 都会变化,文件大小没有变化也是一样。
如果通过充定向的方式改变文件内容(>
or >>
),atime 不会发生变化。
之前有一个测试,可以参考: 2013/04/07, ls 按时间排序
Linux 并没有创建时间,这是令人费解的,可能是早期文件系统没有这个信息吧。
PS: 关于文件的创建时间,参考:2021-12-12 Linux 文件创建时间。
WebDev
2015-01-02
- HRM: Human Resource Management 人力资源管理
- CRM: Customer Relationship Management 客户关系管理
- OA: Office Automation 办公自动化
- ERP: Enterprise Resource Planning 企业资源计划
- SCM: Supply Chain Management
- EAM: Enterprise Asset Management
- FM: Financial Management 财务管理
- PLM: Product Lifecycle Management 产品生命周期管理
- WMS: Warehouse Management System 仓库管理系统
- BPM: Business Process Management 业务流程管理
- MIS: Management Information System 管理信息系统
- EIS: Enterprise Information System 企业信息系统
- OIS: Operations Information System 运营信息系统
- ESS: Enterprise Service System 企业服务系统
- CSM: Customer Service Management 客户服务管理
- BSS: Business Support System 业务支持系统
制造业
- MES: Manufacturing Engineering System 工艺设计系统
建筑业
- BIM: Building Information Model 建筑信息模型
医院
- HIS: Hospital Information System 医院信息化系统
- LIS: Laboratory Information System 化验室信息化系统
- PACS: Patient Administration and Care System 患者管理和护理系统