api-sync.rst (18904B)
1 .. 2 This file is part of GNU TALER. 3 Copyright (C) 2018-2021 Taler Systems SA 4 5 TALER is free software; you can redistribute it and/or modify it under the 6 terms of the GNU Affero General Public License as published by the Free Software 7 Foundation; either version 3.0, or (at your option) any later version. 8 9 TALER is distributed in the hope that it will be useful, but WITHOUT ANY 10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 11 A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. 12 13 You should have received a copy of the GNU Affero General Public License along with 14 TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> 15 16 @author Christian Grothoff 17 18 .. _sync-api: 19 20 ====================================== 21 Backup and Synchronization RESTful API 22 ====================================== 23 24 The backup and synchronization service uses an EdDSA key 25 to identify the "account" of the user. The key is Crockford 26 Base32-encoded in the URI to access the data and used to sign requests 27 as well as to encrypt the contents (see below). These signatures are 28 provided in detached form as HTTP headers. 29 30 Once the user activates backup or synchronization, the client should 31 display the key as a QR code as well as in text format together 32 with the synchronization service's URL and ask the user to print this 33 key material and keep it safe. 34 35 The actual format of the backup is not relevant for the 36 backup and synchronization service, as the service must only ever see 37 a padded and encrypted version of the data. 38 39 However, there are a few general rules that will apply to 40 any version of the backup. Still, except for the 41 32-byte minimum upload size, the synchronization service 42 itself cannot enforce these rules. 43 44 * First, the database should be compressed (i.e. gzip), then 45 padded to a power of 2 in kilobytes or a multiple of 46 megabytes, then encrypted and finally protected with 47 an HDKF. 48 * The encryption should use an SHA-512 nonce which 49 is prefixed to the actual database, and combined with 50 the master key to create the encryption symmetric secret. 51 With every revision of the backup (but only real 52 revisions or merge operations), a fresh nonce must be 53 used to ensure that the symmetric secret differs every 54 time. HKDFs are used to derive symmetric key material 55 for authenticated encryption (encrypt-then-mac or a 56 modern AEAD-cipher like Keccak). Given that AES is more 57 easily available and will likely increase the code of 58 the wallet less, AES plus a SHA-512 HMAC should suffice 59 for now. 60 * The client must enable merging databases in a way that is 61 associative and commutative. For most activities, this implies 62 merging lists, applying expirations, dropping duplicates and 63 sorting the result. For deletions (operations by which the user 64 removed records prior to their scheduled expiration), it means 65 keeping a summarizing log of all deletion operations and applying 66 the deletions after each merge. A summarizing log of a deletion 67 operation would combine two deletion operations of the form 68 "delete all transactions smaller than amount X before time T" and 69 "delete all transactions smaller than amount Y before time T" 70 into "delete all transactions smaller than amount max(X,Y) before 71 time T". Similar summarizations should be applied to all 72 deletion operations supported by the client. Deletion operations 73 themselves are associated with an expiration time reflecting the 74 expiration of the longest lasting record that they explicitly 75 deleted. 76 Purchases do not have an expiration time, thus they create 77 a challenge if an individual purchase is deleted. Thus, when 78 an individual purchase is deleted, the client is to keep track 79 of the deletion with a deletion record. The deletion record 80 still includes the purchase amount and purchase date. Thus, 81 when purchases are deleted "in bulk" in a way that would have 82 covered the individual deletion, such deletion records may 83 still be subsumed by a more general deletion clause. In addition 84 to the date and amount, the deletion record should only contain 85 a salted hash of the original purchase record's primary key, 86 so as to minimize information leakage. 87 * The database should contain a "last modified" timestamp to ensure 88 we do not go backwards in time if the synchronization service is 89 malicious. Merging two databases means taking the max of the 90 "last modified" timestamps, not setting it to the current time. 91 The client should reject a "fast forward" database update if the 92 result would imply going back in time. If the client receives a 93 database with a timestamp into the future, it must still 94 increment it by the smallest possible amount when uploading an 95 update. 96 * In general, the merge operation should be implemented in such a way 97 that it deals gracefully with adversarial devices from rogue 98 devices connected to the same account. 99 100 It is assumed that the synchronization service is only ever accessed 101 over TLS, and that the synchronization service is trusted to not build 102 user's location profiles by linking client IP addresses and client 103 keys. 104 105 .. contents:: Table of Contents 106 :local: 107 108 109 --------------- 110 Version History 111 --------------- 112 113 The current protocol version is **v2**. 114 115 * No components use Sync at this point, so there are no dependencies. 116 117 **Version history:** 118 119 * ``v2``: add the ``implementation`` field to ``/config`` 120 121 **Upcoming versions:** 122 123 * ``vBLOBS``: changes for blob backups 124 * ``vBACKUP``: changes for incremental backups 125 126 **Ideas for future version:** 127 128 * ``vXXX``: marker for features not yet targeted for release 129 130 .. include:: tos.rst 131 132 ----------------------- 133 Receiving Configuration 134 ----------------------- 135 136 .. http:get:: /config 137 138 Obtain the key configuration settings of the storage service. 139 140 **Response:** 141 142 Returns a `SyncTermsOfServiceResponse`. 143 144 .. ts:def:: SyncTermsOfServiceResponse 145 146 interface SyncTermsOfServiceResponse { 147 // Name of the service 148 name: "sync"; 149 150 // Maximum backup size supported. 151 storage_limit_in_megabytes: Integer; 152 153 // Fee for an account, per year. 154 annual_fee: Amount; 155 156 // Maximum liability of the provider in case of data loss. 157 liability_limit: Amount; 158 159 // libtool-style representation of the Sync protocol version, see 160 // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning 161 // The format is "current:revision:age". 162 version: string; 163 164 // Release version of the source code. 165 // The format is MAJOR.MINOR.MICOR[-GITDATA] 166 // and generally follows the "-v" option of the codebase. 167 build_version: string; 168 169 // URN of the implementation (needed to interpret 'revision' in version). 170 // @since **v2**, may become mandatory in the future. 171 implementation?: string; 172 173 } 174 175 .. _sync: 176 177 ---------------------- 178 Recovering Backup Data 179 ---------------------- 180 181 .. http:get:: /backups/${ACCOUNT-KEY} 182 183 Download latest version of the backup. 184 The returned headers must include "Etags" based on 185 the hash of the (encrypted) database. The server must 186 check the client's caching headers and only return the 187 full database if it has changed since the last request 188 of the client. 189 190 This method is generally only performed once per device 191 when the private key and URL of a synchronization service are 192 first given to the client on the respective device. Once a 193 client has made a backup, it should always use the POST method. 194 195 A signature is not required, as (1) the account-key should 196 be reasonably private and thus unauthorized users should not 197 know how to produce the correct request, and (2) the 198 information returned is encrypted to the private key anyway 199 and thus virtually useless even to an attacker who somehow 200 managed to obtain the public key. 201 202 **Response** 203 204 :http:statuscode:`200 OK`: 205 The body contains the current version of the backup 206 as known to the server. 207 208 :http:statuscode:`204 No content`: 209 This is a fresh account, no previous backup data exists at 210 the server. 211 212 :http:statuscode:`304 Not modified`: 213 The version available at the server is identical to that 214 specified in the ``If-None-Match`` header. 215 216 :http:statuscode:`404 Not found`: 217 The backup service is unaware of a matching account. 218 219 :http:statuscode:`410 Gone`: 220 The backup service has closed operations. The body will 221 contain the latest version still available at the server. 222 The body may be empty if no version is available. 223 The user should be urged to find another provider. 224 225 :http:statuscode:`429 Too many requests`: 226 This account has exceeded thresholds for the number of 227 requests. The client should try again later, and may want 228 to decrease its synchronization frequency. 229 230 .. note:: 231 232 "200 OK" responses include an HTTP header 233 "Sync-Signature" with the signature of the 234 client from the original upload, and an 235 "Sync-Previous" with the version that was 236 being updated (unless this is the first revision). 237 "Sync-Previous" is only given to enable 238 signature validation. 239 240 241 --------------------- 242 Uploading Backup Data 243 --------------------- 244 245 .. http:post:: /backups/${ACCOUNT-KEY} 246 247 Upload a new version of the account's database, or download the 248 latest version. The request SHOULD include the ``Expect: 100 Continue`` 249 header. The client then SHOULD wait for ``100 Continue`` before proceeding 250 with the upload, regardless of the size of the upload. 251 252 **Request** 253 254 The request must include a ``If-Match`` header indicating the latest 255 version of the account's database known to the client. If the server 256 knows a more recent version, it will respond with a ``409 conflict`` 257 and return the server's version in the response. The client must 258 then merge the two versions before retrying the upload. Note that 259 a ``409 Conflict`` response will typically be given before the upload, 260 (instead of ``100 continue``), but may also be given after the upload, 261 for example due to concurrent activities from other accounts on the 262 same account! 263 264 The request MUST also include an "Sync-Signature" signing 265 the ``If-Match`` SHA-512 value and the SHA-512 hash of the body with 266 the account private key. 267 268 Finally, the SHA-512 hash of the body MUST also be given in an 269 ``If-None-Match`` header of the request (so that the signature can be verified 270 before the upload is allowed to proceed). 271 272 The uploaded body must have at least 32 bytes of payload (see 273 suggested upload format beginning with an ephemeral key). 274 275 :query paying: 276 Optional argument providing an order identifier. 277 The client is promising that it is already paying on a 278 related order. This will cause the 279 server to delay processing until the respective payment 280 has arrived (if the operation requires a payment). Useful 281 if the server previously returned a ``402 Payment required`` 282 and the client wants to proceed as soon as the payment 283 went through. 284 :query pay: 285 Optional argument, any non-empty value will do, 286 suggested is ``y`` for ``yes``. 287 The client insists on making a payment for the respective 288 account, even if this is not yet required. The server 289 will respond with a ``402 Payment required``, but only 290 if the rest of the request is well-formed (account 291 signature must match). Clients that do not actually 292 intend to make a new upload but that only want to pay 293 may attempt to upload the latest backup again, as this 294 option will be checked before the ``304 Not modified`` 295 case. 296 :query fresh: 297 Optional argument, any non-empty value will do, 298 suggested is ``y`` for ``yes``. 299 The client insists on a fresh order to be generated, say 300 because the one returned before was claimed (but not paid) 301 by another wallet. 302 303 304 **Response** 305 306 :http:statuscode:`204 No content`: 307 The transfer was successful, and the server has registered 308 the new version. 309 310 :http:statuscode:`304 Not modified`: 311 The server is already aware of this version of the client. 312 Returned before ``100 continue`` to avoid upload. 313 FIXME: Might be better to use ``412 Precondition Failed`` here 314 in the future! 315 316 :http:statuscode:`400 Bad request`: 317 Most likely, the uploaded body is too short (less than 32 bytes). 318 319 :http:statuscode:`402 Payment required`: 320 The synchronization service requires payment before the 321 account can continue to be used. The fulfillment URL 322 should be the ``/$ACCOUNT-KEY`` URL, but can be safely ignored 323 by the client. The contract should be shown to the user 324 in the canonical dialog, possibly in a fresh tab. 325 326 :http:statuscode:`403 Forbidden`: 327 The signature is invalid or missing (or body does not match). 328 329 :http:statuscode:`409 Conflict`: 330 The server has a more recent version than what is given 331 in ``If-Match``. The more recent version is returned. The 332 client should merge the two versions and retry using the 333 given response's "E-Tag" in the next attempt in ``If-Match``. 334 335 :http:statuscode:`410 Gone`: 336 The backup service has closed operations. The body will 337 contain the latest version still available at the server. 338 The body may be empty if no version is available. 339 The user should be urged to find another provider. 340 341 :http:statuscode:`411 Length required`: 342 The client must specify the ``Content-length`` header before 343 attempting upload. While technically optional by the 344 HTTP specification, the synchronization service may require 345 the client to provide the length upfront. 346 347 :http:statuscode:`413 Request entity too large`: 348 The requested upload exceeds the quota for the type of 349 account. The client should suggest to the user to 350 migrate to another backup and synchronization service 351 (like with ``410 Gone``). 352 353 :http:statuscode:`429 Too many requests`: 354 This account has exceeded daily thresholds for the number of 355 requests. The client should try again later, and may want 356 to decrease its synchronization frequency. 357 358 .. note:: 359 360 Responses with a body include an HTTP header 361 "Sync-Signature" with the signature of the 362 client from the original upload, and an 363 "If-Match" with the version that is 364 being updated (unless this is the first revision). 365 366 367 368 --------------------------- 369 Special constraints for Tor 370 --------------------------- 371 372 We might introduce the notion of a "constraint" into the client's 373 database that states that the database is a "Tor wallet". Then, 374 synchronizing a "Tor-wallet" with a non-Tor wallet should trigger a 375 stern warning and require user confirmation (as otherwise 376 cross-browser synchronization may weaken the security of Tor browser 377 users). 378 379 380 ------------------------------------------------ 381 Discovery of backup and synchronization services 382 ------------------------------------------------ 383 384 The client should keep a list of "default" synchronization services 385 per currency (by the currency the synchronization service accepts 386 for payment). If a synchronization service is entirely free, it 387 should be kept in a special list that is always available. 388 389 Extending (or shortening) the list of synchronization services should 390 be possible using the same mechanism that is used to add/remove 391 auditors or exchanges. 392 393 The client should urge the user to make use of a synchronization 394 service upon first withdrawal, suggesting one that is free or 395 accepts payment in the respective currency. If none is available, 396 the client should warn the user about the lack of available 397 backups and synchronization and suggest to the user to find a 398 reasonable service. Once a synchronization service is selected, 399 the client should urge the user to print the respective key 400 material. 401 402 When the client starts the first time on a new device, it should 403 ask the user if he wants to synchronize with an existing client, 404 and if so, ask the user to enter the respective key and the 405 (base) URL of the synchronization service. 406 407 408 ------------------------- 409 Synchronization frequency 410 ------------------------- 411 412 Generally, the client should attempt to synchronize at a randomized 413 time interval between 30 and 300 seconds of being started, unless it 414 already synchronized less than two hours ago already. Afterwards, 415 the client should synchronize every two hours, or after purchases 416 exceed 5 percent of the last bulk amount that the user withdrew. 417 In all cases the exact time of synchronization should be randomized 418 between 30 and 300 seconds of the specified event, both to minimize 419 obvious correlations and to spread the load. 420 421 If the two hour frequency would exceed half of the rate budget offered 422 by the synchronization provider, it should be reduced to remain below 423 that threshold. 424 425 426 ------------------------------- 427 Synchronization user experience 428 ------------------------------- 429 430 The menu should include three entries for synchronization: 431 432 * "synchronize" to manually trigger synchronization, 433 insensitive if no synchronization provider is available 434 * "export backup configuration" to re-display (and possibly 435 print) the synchronization and backup parameters (URL and 436 private key), insensitive if no synchronization 437 provider is available, and 438 * "import backup configuration" to: 439 440 * import another device's synchronization options 441 (by specifying URL and private key, or possibly 442 scanning a QR code), or 443 * select a synchronization provider from the list, 444 including manual specification of a URL; here 445 confirmation should only be possible if the provider 446 is free or can be paid for; in this case, the 447 client should trigger the payment interaction when 448 the user presses the "select" button. 449 * a special button to "disable synchronization and backup" 450 451 One usability issue here is that we are asking users to deal with a 452 private key. It is likely better to map private keys to trustwords 453 (PEP-style). Also, when putting private keys into a QR code, there is 454 the danger of the QR code being scanned and interpreted as a "public" 455 URL. Thus, the QR code should use the schema 456 ``taler://sync/$SYNC-DOMAIN/$SYNC-PATH#private-key`` where 457 ``$SYNC-DOMAIN`` is the domainname of the synchronization service and 458 ``$SYNC-PATH`` the (usually empty) path. By putting the private key after 459 ``#``, we may succeed in disclosing the value even to eager Web-ish 460 interpreters of URLs. Note that the actual synchronization service 461 must use the HTTPS protocol, which means we can leave out this prefix. 462 463 464 --------------------------- 465 Web Security Considerations 466 --------------------------- 467 468 To ensure that the Taler Web extension (and others) can access the 469 service despite Web "security", all service endpoints must set the 470 header:: 471 472 Access-Control-Allow-Origin: *