security.py 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. # -*- coding: utf-8 -*-
  2. """
  3. werkzeug.security
  4. ~~~~~~~~~~~~~~~~~
  5. Security related helpers such as secure password hashing tools.
  6. :copyright: (c) 2014 by the Werkzeug Team, see AUTHORS for more details.
  7. :license: BSD, see LICENSE for more details.
  8. """
  9. import os
  10. import hmac
  11. import hashlib
  12. import posixpath
  13. import codecs
  14. from struct import Struct
  15. from random import SystemRandom
  16. from operator import xor
  17. from itertools import starmap
  18. from werkzeug._compat import range_type, PY2, text_type, izip, to_bytes, \
  19. string_types, to_native
  20. SALT_CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
  21. DEFAULT_PBKDF2_ITERATIONS = 50000
  22. _pack_int = Struct('>I').pack
  23. _builtin_safe_str_cmp = getattr(hmac, 'compare_digest', None)
  24. _sys_rng = SystemRandom()
  25. _os_alt_seps = list(sep for sep in [os.path.sep, os.path.altsep]
  26. if sep not in (None, '/'))
  27. def _find_hashlib_algorithms():
  28. algos = getattr(hashlib, 'algorithms', None)
  29. if algos is None:
  30. algos = ('md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512')
  31. rv = {}
  32. for algo in algos:
  33. func = getattr(hashlib, algo, None)
  34. if func is not None:
  35. rv[algo] = func
  36. return rv
  37. _hash_funcs = _find_hashlib_algorithms()
  38. def pbkdf2_hex(data, salt, iterations=DEFAULT_PBKDF2_ITERATIONS,
  39. keylen=None, hashfunc=None):
  40. """Like :func:`pbkdf2_bin`, but returns a hex-encoded string.
  41. .. versionadded:: 0.9
  42. :param data: the data to derive.
  43. :param salt: the salt for the derivation.
  44. :param iterations: the number of iterations.
  45. :param keylen: the length of the resulting key. If not provided,
  46. the digest size will be used.
  47. :param hashfunc: the hash function to use. This can either be the
  48. string name of a known hash function, or a function
  49. from the hashlib module. Defaults to sha256.
  50. """
  51. rv = pbkdf2_bin(data, salt, iterations, keylen, hashfunc)
  52. return to_native(codecs.encode(rv, 'hex_codec'))
  53. _has_native_pbkdf2 = hasattr(hashlib, 'pbkdf2_hmac')
  54. def pbkdf2_bin(data, salt, iterations=DEFAULT_PBKDF2_ITERATIONS,
  55. keylen=None, hashfunc=None):
  56. """Returns a binary digest for the PBKDF2 hash algorithm of `data`
  57. with the given `salt`. It iterates `iterations` times and produces a
  58. key of `keylen` bytes. By default, SHA-256 is used as hash function;
  59. a different hashlib `hashfunc` can be provided.
  60. .. versionadded:: 0.9
  61. :param data: the data to derive.
  62. :param salt: the salt for the derivation.
  63. :param iterations: the number of iterations.
  64. :param keylen: the length of the resulting key. If not provided
  65. the digest size will be used.
  66. :param hashfunc: the hash function to use. This can either be the
  67. string name of a known hash function or a function
  68. from the hashlib module. Defaults to sha256.
  69. """
  70. if isinstance(hashfunc, string_types):
  71. hashfunc = _hash_funcs[hashfunc]
  72. elif not hashfunc:
  73. hashfunc = hashlib.sha256
  74. data = to_bytes(data)
  75. salt = to_bytes(salt)
  76. # If we're on Python with pbkdf2_hmac we can try to use it for
  77. # compatible digests.
  78. if _has_native_pbkdf2:
  79. _test_hash = hashfunc()
  80. if hasattr(_test_hash, 'name') and \
  81. _test_hash.name in _hash_funcs:
  82. return hashlib.pbkdf2_hmac(_test_hash.name,
  83. data, salt, iterations,
  84. keylen)
  85. mac = hmac.HMAC(data, None, hashfunc)
  86. if not keylen:
  87. keylen = mac.digest_size
  88. def _pseudorandom(x, mac=mac):
  89. h = mac.copy()
  90. h.update(x)
  91. return bytearray(h.digest())
  92. buf = bytearray()
  93. for block in range_type(1, -(-keylen // mac.digest_size) + 1):
  94. rv = u = _pseudorandom(salt + _pack_int(block))
  95. for i in range_type(iterations - 1):
  96. u = _pseudorandom(bytes(u))
  97. rv = bytearray(starmap(xor, izip(rv, u)))
  98. buf.extend(rv)
  99. return bytes(buf[:keylen])
  100. def safe_str_cmp(a, b):
  101. """This function compares strings in somewhat constant time. This
  102. requires that the length of at least one string is known in advance.
  103. Returns `True` if the two strings are equal, or `False` if they are not.
  104. .. versionadded:: 0.7
  105. """
  106. if isinstance(a, text_type):
  107. a = a.encode('utf-8')
  108. if isinstance(b, text_type):
  109. b = b.encode('utf-8')
  110. if _builtin_safe_str_cmp is not None:
  111. return _builtin_safe_str_cmp(a, b)
  112. if len(a) != len(b):
  113. return False
  114. rv = 0
  115. if PY2:
  116. for x, y in izip(a, b):
  117. rv |= ord(x) ^ ord(y)
  118. else:
  119. for x, y in izip(a, b):
  120. rv |= x ^ y
  121. return rv == 0
  122. def gen_salt(length):
  123. """Generate a random string of SALT_CHARS with specified ``length``."""
  124. if length <= 0:
  125. raise ValueError('Salt length must be positive')
  126. return ''.join(_sys_rng.choice(SALT_CHARS) for _ in range_type(length))
  127. def _hash_internal(method, salt, password):
  128. """Internal password hash helper. Supports plaintext without salt,
  129. unsalted and salted passwords. In case salted passwords are used
  130. hmac is used.
  131. """
  132. if method == 'plain':
  133. return password, method
  134. if isinstance(password, text_type):
  135. password = password.encode('utf-8')
  136. if method.startswith('pbkdf2:'):
  137. args = method[7:].split(':')
  138. if len(args) not in (1, 2):
  139. raise ValueError('Invalid number of arguments for PBKDF2')
  140. method = args.pop(0)
  141. iterations = args and int(args[0] or 0) or DEFAULT_PBKDF2_ITERATIONS
  142. is_pbkdf2 = True
  143. actual_method = 'pbkdf2:%s:%d' % (method, iterations)
  144. else:
  145. is_pbkdf2 = False
  146. actual_method = method
  147. hash_func = _hash_funcs.get(method)
  148. if hash_func is None:
  149. raise TypeError('invalid method %r' % method)
  150. if is_pbkdf2:
  151. if not salt:
  152. raise ValueError('Salt is required for PBKDF2')
  153. rv = pbkdf2_hex(password, salt, iterations,
  154. hashfunc=hash_func)
  155. elif salt:
  156. if isinstance(salt, text_type):
  157. salt = salt.encode('utf-8')
  158. rv = hmac.HMAC(salt, password, hash_func).hexdigest()
  159. else:
  160. h = hash_func()
  161. h.update(password)
  162. rv = h.hexdigest()
  163. return rv, actual_method
  164. def generate_password_hash(password, method='pbkdf2:sha256', salt_length=8):
  165. """Hash a password with the given method and salt with a string of
  166. the given length. The format of the string returned includes the method
  167. that was used so that :func:`check_password_hash` can check the hash.
  168. The format for the hashed string looks like this::
  169. method$salt$hash
  170. This method can **not** generate unsalted passwords but it is possible
  171. to set param method='plain' in order to enforce plaintext passwords.
  172. If a salt is used, hmac is used internally to salt the password.
  173. If PBKDF2 is wanted it can be enabled by setting the method to
  174. ``pbkdf2:method:iterations`` where iterations is optional::
  175. pbkdf2:sha256:80000$salt$hash
  176. pbkdf2:sha256$salt$hash
  177. :param password: the password to hash.
  178. :param method: the hash method to use (one that hashlib supports). Can
  179. optionally be in the format ``pbkdf2:<method>[:iterations]``
  180. to enable PBKDF2.
  181. :param salt_length: the length of the salt in letters.
  182. """
  183. salt = method != 'plain' and gen_salt(salt_length) or ''
  184. h, actual_method = _hash_internal(method, salt, password)
  185. return '%s$%s$%s' % (actual_method, salt, h)
  186. def check_password_hash(pwhash, password):
  187. """check a password against a given salted and hashed password value.
  188. In order to support unsalted legacy passwords this method supports
  189. plain text passwords, md5 and sha1 hashes (both salted and unsalted).
  190. Returns `True` if the password matched, `False` otherwise.
  191. :param pwhash: a hashed string like returned by
  192. :func:`generate_password_hash`.
  193. :param password: the plaintext password to compare against the hash.
  194. """
  195. if pwhash.count('$') < 2:
  196. return False
  197. method, salt, hashval = pwhash.split('$', 2)
  198. return safe_str_cmp(_hash_internal(method, salt, password)[0], hashval)
  199. def safe_join(directory, *pathnames):
  200. """Safely join `directory` and one or more untrusted `pathnames`. If this
  201. cannot be done, this function returns ``None``.
  202. :param directory: the base directory.
  203. :param pathnames: the untrusted pathnames relative to that directory.
  204. """
  205. parts = [directory]
  206. for filename in pathnames:
  207. if filename != '':
  208. filename = posixpath.normpath(filename)
  209. for sep in _os_alt_seps:
  210. if sep in filename:
  211. return None
  212. if os.path.isabs(filename) or \
  213. filename == '..' or \
  214. filename.startswith('../'):
  215. return None
  216. parts.append(filename)
  217. return posixpath.join(*parts)