security.rst 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. .. include:: ../global.rst.inc
  2. .. somewhat surprisingly the "bash" highlighter gives nice results with
  3. the pseudo-code notation used in the "Encryption" section.
  4. .. highlight:: bash
  5. ========
  6. Security
  7. ========
  8. .. _borgcrypto:
  9. Cryptography in Borg
  10. ====================
  11. .. _attack_model:
  12. Attack model
  13. ------------
  14. The attack model of Borg is that the environment of the client process
  15. (e.g. ``borg create``) is trusted and the repository (server) is not. The
  16. attacker has any and all access to the repository, including interactive
  17. manipulation (man-in-the-middle) for remote repositories.
  18. Furthermore the client environment is assumed to be persistent across
  19. attacks (practically this means that the security database cannot be
  20. deleted between attacks).
  21. Under these circumstances Borg guarantees that the attacker cannot
  22. 1. modify the data of any archive without the client detecting the change
  23. 2. rename, remove or add an archive without the client detecting the change
  24. 3. recover plain-text data
  25. 4. recover definite (heuristics based on access patterns are possible)
  26. structural information such as the object graph (which archives
  27. refer to what chunks)
  28. The attacker can always impose a denial of service per definition (he could
  29. forbid connections to the repository, or delete it entirely).
  30. .. _security_structural_auth:
  31. Structural Authentication
  32. -------------------------
  33. Borg is fundamentally based on an object graph structure (see :ref:`internals`),
  34. where the root object is called the manifest.
  35. Borg follows the `Horton principle`_, which states that
  36. not only the message must be authenticated, but also its meaning (often
  37. expressed through context), because every object used is referenced by a
  38. parent object through its object ID up to the manifest. The object ID in
  39. Borg is a MAC of the object's plaintext, therefore this ensures that
  40. an attacker cannot change the context of an object without forging the MAC.
  41. In other words, the object ID itself only authenticates the plaintext of the
  42. object and not its context or meaning. The latter is established by a different
  43. object referring to an object ID, thereby assigning a particular meaning to
  44. an object. For example, an archive item contains a list of object IDs that
  45. represent packed file metadata. On their own it's not clear that these objects
  46. would represent what they do, but by the archive item referring to them
  47. in a particular part of its own data structure assigns this meaning.
  48. This results in a directed acyclic graph of authentication from the manifest
  49. to the data chunks of individual files.
  50. .. _tam_description:
  51. .. rubric:: Authenticating the manifest
  52. Since the manifest has a fixed ID (000...000) the aforementioned authentication
  53. does not apply to it, indeed, cannot apply to it; it is impossible to authenticate
  54. the root node of a DAG through its edges, since the root node has no incoming edges.
  55. With the scheme as described so far an attacker could easily replace the manifest,
  56. therefore Borg includes a tertiary authentication mechanism (TAM) that is applied
  57. to the manifest (see :ref:`tam_vuln`).
  58. TAM works by deriving a separate key through HKDF_ from the other encryption and
  59. authentication keys and calculating the HMAC of the metadata to authenticate [#]_::
  60. # RANDOM(n) returns n random bytes
  61. salt = RANDOM(64)
  62. ikm = id_key || crypt_key
  63. # *context* depends on the operation, for manifest authentication it is
  64. # the ASCII string "borg-metadata-authentication-manifest".
  65. tam_key = HKDF-SHA-512(ikm, salt, context)
  66. # *data* is a dict-like structure
  67. data[hmac] = zeroes
  68. packed = pack(data)
  69. data[hmac] = HMAC(tam_key, packed)
  70. packed_authenticated = pack(data)
  71. Since an attacker cannot gain access to this key and also cannot make the
  72. client authenticate arbitrary data using this mechanism, the attacker is unable
  73. to forge the authentication.
  74. This effectively 'anchors' the manifest to the key, which is controlled by the
  75. client, thereby anchoring the entire DAG, making it impossible for an attacker
  76. to add, remove or modify any part of the DAG without Borg being able to detect
  77. the tampering.
  78. Note that when using BORG_PASSPHRASE the attacker cannot swap the *entire*
  79. repository against a new repository with e.g. repokey mode and no passphrase,
  80. because Borg will abort access when BORG_PASSPHRASE is incorrect.
  81. However, interactively a user might not notice this kind of attack
  82. immediately, if she assumes that the reason for the absent passphrase
  83. prompt is a set BORG_PASSPHRASE. See issue :issue:`2169` for details.
  84. .. [#] The reason why the authentication tag is stored in the packed
  85. data itself is that older Borg versions can still read the
  86. manifest this way, while a changed layout would have broken
  87. compatibility.
  88. .. _security_encryption:
  89. Encryption
  90. ----------
  91. AEAD modes
  92. ~~~~~~~~~~
  93. Modes: --encryption (repokey|keyfile)-[blake2-](aes-ocb|chacha20-poly1305)
  94. Supported: borg 2.0+
  95. Encryption with these modes is based on AEAD ciphers (authenticated encryption
  96. with associated data) and session keys.
  97. Depending on the chosen mode (see :ref:`borg_rcreate`) different AEAD ciphers are used:
  98. - AES-256-OCB - super fast, single-pass algorithm IF you have hw accelerated AES.
  99. - chacha20-poly1305 - very fast, purely software based AEAD cipher.
  100. The chunk ID is derived via a MAC over the plaintext (mac key taken from borg key):
  101. - HMAC-SHA256 - super fast IF you have hw accelerated SHA256 (see section "Encryption" below).
  102. - Blake2b - very fast, purely software based algorithm.
  103. For each borg invocation, a new session id is generated by `os.urandom`_.
  104. From that session id, the initial key material (ikm, taken from the borg key)
  105. and an application and cipher specific salt, borg derives a session key via HKDF.
  106. For each session key, IVs (nonces) are generated by a counter which increments for
  107. each encrypted message.
  108. Session::
  109. sessionid = os.urandom(24)
  110. ikm = crypt_key
  111. salt = "borg-session-key-CIPHERNAME"
  112. sessionkey = HKDF(ikm, sessionid, salt)
  113. message_iv = 0
  114. Encryption::
  115. id = MAC(id_key, data)
  116. compressed = compress(data)
  117. header = type-byte || 00h || message_iv || sessionid
  118. aad = id || header
  119. message_iv++
  120. encrypted, auth_tag = AEAD_encrypt(session_key, message_iv, compressed, aad)
  121. authenticated = header || auth_tag || encrypted
  122. Decryption::
  123. # Given: input *authenticated* data and a *chunk-id* to assert
  124. type-byte, past_message_iv, past_sessionid, auth_tag, encrypted = SPLIT(authenticated)
  125. ASSERT(type-byte is correct)
  126. past_key = HKDF(ikm, past_sessionid, salt)
  127. decrypted = AEAD_decrypt(past_key, past_message_iv, authenticated)
  128. decompressed = decompress(decrypted)
  129. Notable:
  130. - More modern and often faster AEAD ciphers instead of self-assembled stuff.
  131. - Due to the usage of session keys, IVs (nonces) do not need special care here as
  132. they did for the legacy encryption modes.
  133. - The id is now also input into the authentication tag computation.
  134. This strongly associates the id with the written data (== associates the key with
  135. the value). When later reading the data for some id, authentication will only
  136. succeed if what we get was really written by us for that id.
  137. Legacy modes
  138. ~~~~~~~~~~~~
  139. Modes: --encryption (repokey|keyfile)-[blake2]
  140. Supported: borg < 2.0
  141. These were the AES-CTR based modes in previous borg versions.
  142. borg 2.0 does not support creating new repos using these modes,
  143. but ``borg transfer`` can still read such existing repos.
  144. .. _key_encryption:
  145. Offline key security
  146. --------------------
  147. Borg cannot secure the key material while it is running, because the keys
  148. are needed in plain to decrypt/encrypt repository objects.
  149. For offline storage of the encryption keys they are encrypted with a
  150. user-chosen passphrase.
  151. A 256 bit key encryption key (KEK) is derived from the passphrase
  152. using argon2_ with a random 256 bit salt. The KEK is then used
  153. to Encrypt-*then*-MAC a packed representation of the keys using the
  154. chacha20-poly1305 AEAD cipher and a constant IV == 0.
  155. The ciphertext is then converted to base64.
  156. This base64 blob (commonly referred to as *keyblob*) is then stored in
  157. the key file or in the repository config (keyfile and repokey modes
  158. respectively).
  159. The use of a constant IV is secure because an identical passphrase will
  160. result in a different derived KEK for every key encryption due to the salt.
  161. .. seealso::
  162. Refer to the :ref:`key_files` section for details on the format.
  163. Implementations used
  164. --------------------
  165. We do not implement cryptographic primitives ourselves, but rely
  166. on widely used libraries providing them:
  167. - AES-OCB and CHACHA20-POLY1305 from OpenSSL 1.1 are used,
  168. which is also linked into the static binaries we provide.
  169. We think this is not an additional risk, since we don't ever
  170. use OpenSSL's networking, TLS or X.509 code, but only their
  171. primitives implemented in libcrypto.
  172. - SHA-256, SHA-512 and BLAKE2b from Python's hashlib_ standard library module are used.
  173. - HMAC and a constant-time comparison from Python's hmac_ standard library module are used.
  174. - argon2 is used via argon2-cffi.
  175. Implemented cryptographic constructions are:
  176. - HKDF_-SHA-512 (using ``hmac.digest`` from Python's hmac_ standard library module)
  177. .. _Horton principle: https://en.wikipedia.org/wiki/Horton_Principle
  178. .. _HKDF: https://tools.ietf.org/html/rfc5869
  179. .. _length extension: https://en.wikipedia.org/wiki/Length_extension_attack
  180. .. _hashlib: https://docs.python.org/3/library/hashlib.html
  181. .. _hmac: https://docs.python.org/3/library/hmac.html
  182. .. _os.urandom: https://docs.python.org/3/library/os.html#os.urandom
  183. Remote RPC protocol security
  184. ============================
  185. .. note:: This section could be further expanded / detailed.
  186. The RPC protocol is fundamentally based on msgpack'd messages exchanged
  187. over an encrypted SSH channel (the system's SSH client is used for this
  188. by piping data from/to it).
  189. This means that the authorization and transport security properties
  190. are inherited from SSH and the configuration of the SSH client and the
  191. SSH server -- Borg RPC does not contain *any* networking
  192. code. Networking is done by the SSH client running in a separate
  193. process, Borg only communicates over the standard pipes (stdout,
  194. stderr and stdin) with this process. This also means that Borg doesn't
  195. have to directly use a SSH client (or SSH at all). For example,
  196. ``sudo`` or ``qrexec`` could be used as an intermediary.
  197. By using the system's SSH client and not implementing a
  198. (cryptographic) network protocol Borg sidesteps many security issues
  199. that would normally impact distributing statically linked / standalone
  200. binaries.
  201. The remainder of this section will focus on the security of the RPC
  202. protocol within Borg.
  203. The assumed worst-case a server can inflict to a client is a
  204. denial of repository service.
  205. The situation where a server can create a general DoS on the client
  206. should be avoided, but might be possible by e.g. forcing the client to
  207. allocate large amounts of memory to decode large messages (or messages
  208. that merely indicate a large amount of data follows). The RPC protocol
  209. code uses a limited msgpack Unpacker to prohibit this.
  210. We believe that other kinds of attacks, especially critical vulnerabilities
  211. like remote code execution are inhibited by the design of the protocol:
  212. 1. The server cannot send requests to the client on its own accord,
  213. it only can send responses. This avoids "unexpected inversion of control"
  214. issues.
  215. 2. msgpack serialization does not allow embedding or referencing code that
  216. is automatically executed. Incoming messages are unpacked by the msgpack
  217. unpacker into native Python data structures (like tuples and dictionaries),
  218. which are then passed to the rest of the program.
  219. Additional verification of the correct form of the responses could be implemented.
  220. 3. Remote errors are presented in two forms:
  221. 1. A simple plain-text *stderr* channel. A prefix string indicates the kind of message
  222. (e.g. WARNING, INFO, ERROR), which is used to suppress it according to the
  223. log level selected in the client.
  224. A server can send arbitrary log messages, which may confuse a user. However,
  225. log messages are only processed when server requests are in progress, therefore
  226. the server cannot interfere / confuse with security critical dialogue like
  227. the password prompt.
  228. 2. Server-side exceptions passed over the main data channel. These follow the
  229. general pattern of server-sent responses and are sent instead of response data
  230. for a request.
  231. The msgpack implementation used (msgpack-python) has a good security track record,
  232. a large test suite and no issues found by fuzzing. It is based on the msgpack-c implementation,
  233. sharing the unpacking engine and some support code. msgpack-c has a good track record as well.
  234. Some issues [#]_ in the past were located in code not included in msgpack-python.
  235. Borg does not use msgpack-c.
  236. .. [#] - `MessagePack fuzzing <https://blog.gypsyengineer.com/fun/msgpack-fuzzing.html>`_
  237. - `Fixed integer overflow and EXT size problem <https://github.com/msgpack/msgpack-c/pull/547>`_
  238. - `Fixed array and map size overflow <https://github.com/msgpack/msgpack-c/pull/550>`_
  239. Using OpenSSL
  240. =============
  241. Borg uses the OpenSSL library for most cryptography (see `Implementations used`_ above).
  242. OpenSSL is bundled with static releases, thus the bundled copy is not updated with system
  243. updates.
  244. OpenSSL is a large and complex piece of software and has had its share of vulnerabilities,
  245. however, it is important to note that Borg links against ``libcrypto`` **not** ``libssl``.
  246. libcrypto is the low-level cryptography part of OpenSSL,
  247. while libssl implements TLS and related protocols.
  248. The latter is not used by Borg (cf. `Remote RPC protocol security`_, Borg itself does not implement
  249. any network access) and historically contained most vulnerabilities, especially critical ones.
  250. The static binaries released by the project contain neither libssl nor the Python ssl/_ssl modules.
  251. Compression and Encryption
  252. ==========================
  253. Combining encryption with compression can be insecure in some contexts (e.g. online protocols).
  254. There was some discussion about this in :issue:`1040` and for Borg some developers
  255. concluded this is no problem at all, some concluded this is hard and extremely slow to exploit
  256. and thus no problem in practice.
  257. No matter what, there is always the option not to use compression if you are worried about this.
  258. Fingerprinting
  259. ==============
  260. Stored chunk sizes
  261. ------------------
  262. A borg repository does not hide the size of the chunks it stores (size
  263. information is needed to operate the repository).
  264. The chunks stored in the repo are the (compressed, encrypted and authenticated)
  265. output of the chunker. The sizes of these stored chunks are influenced by the
  266. compression, encryption and authentication.
  267. buzhash chunker
  268. ~~~~~~~~~~~~~~~
  269. The buzhash chunker chunks according to the input data, the chunker's
  270. parameters and the secret chunker seed (which all influence the chunk boundary
  271. positions).
  272. Small files below some specific threshold (default: 512 KiB) result in only one
  273. chunk (identical content / size as the original file), bigger files result in
  274. multiple chunks.
  275. fixed chunker
  276. ~~~~~~~~~~~~~
  277. This chunker yields fixed sized chunks, with optional support of a differently
  278. sized header chunk. The last chunk is not required to have the full block size
  279. and is determined by the input file size.
  280. Within our attack model, an attacker possessing a specific set of files which
  281. he assumes that the victim also possesses (and backups into the repository)
  282. could try a brute force fingerprinting attack based on the chunk sizes in the
  283. repository to prove his assumption.
  284. To make this more difficult, borg has an ``obfuscate`` pseudo compressor, that
  285. will take the output of the normal compression step and tries to obfuscate
  286. the size of that output. Of course, it can only **add** to the size, not reduce
  287. it. Thus, the optional usage of this mechanism comes at a cost: it will make
  288. your repository larger (ranging from a few percent larger [cheap] to ridiculously
  289. larger [expensive], depending on the algorithm/params you wisely choose).
  290. The output of the compressed-size obfuscation step will then be encrypted and
  291. authenticated, as usual. Of course, using that obfuscation would not make any
  292. sense without encryption. Thus, the additional data added by the obfuscator
  293. are just 0x00 bytes, which is good enough because after encryption it will
  294. look like random anyway.
  295. To summarize, this is making size-based fingerprinting difficult:
  296. - user-selectable chunker algorithm (and parametrization)
  297. - for the buzhash chunker: secret, random per-repo chunker seed
  298. - user-selectable compression algorithm (and level)
  299. - optional ``obfuscate`` pseudo compressor with different choices
  300. of algorithm and parameters
  301. Secret key usage against fingerprinting
  302. ---------------------------------------
  303. Borg uses the borg key also for chunking and chunk ID generation to protect against fingerprinting.
  304. As usual for borg's attack model, the attacker is assumed to have access to a borg repository.
  305. The borg key includes a secret random chunk_seed which (together with the chunking algorithm)
  306. determines the cutting places and thereby the length of the chunks cut. Because the attacker trying
  307. a chunk length fingerprinting attack would use a different chunker secret than the borg setup being
  308. attacked, they would not be able to determine the set of chunk lengths for a known set of files.
  309. The borg key also includes a secret random id_key. The chunk ID generation is not just using a simple
  310. cryptographic hash like sha256 (because that would be insecure as an attacker could see the hashes of
  311. small files that result only in 1 chunk in the repository). Instead, borg uses keyed hash (a MAC,
  312. e.g. HMAC-SHA256) to compute the chunk ID from the content and the secret id_key. Thus, an attacker
  313. can't compute the same chunk IDs for a known set of small files to determine whether these are stored
  314. in the attacked repository.
  315. Stored chunk proximity
  316. ----------------------
  317. Borg does not try to obfuscate order / proximity of files it discovers by
  318. recursing through the filesystem. For performance reasons, we sort directory
  319. contents in file inode order (not in file name alphabetical order), so order
  320. fingerprinting is not useful for an attacker.
  321. But, when new files are close to each other (when looking at recursion /
  322. scanning order), the resulting chunks will be also stored close to each other
  323. in the resulting repository segment file(s).
  324. This might leak additional information for the chunk size fingerprinting
  325. attack (see above).