浏览代码

feat(auth): use base64 encoded tokens

Using base64 rather than hex notation for tokens saves some length
in their ASCII (utf-8) representation, without weakening security.
This commit in fact increases security by 8 bit, using 21 random
bytes for tokens rather than 20 bytes (this is due to some padding
in base64, so 20 bytes and 21 bytes will both be represented by
28 chars in base64).

Old tokens in hex representation will remain vaild.
Nils Wisiol 6 年之前
父节点
当前提交
d068c2aa85
共有 4 个文件被更改,包括 13 次插入5 次删除
  1. 5 0
      api/desecapi/models.py
  2. 2 0
      test/e2e/schemas.js
  3. 4 4
      test/e2e/spec/api_spec.js
  4. 2 1
      test/e2e/spec/dyndns_spec.js

+ 5 - 0
api/desecapi/models.py

@@ -9,6 +9,8 @@ from django.core.validators import MinValueValidator
 from collections import OrderedDict
 import rest_framework.authtoken.models
 from time import time
+from os import urandom
+from base64 import b64encode
 
 
 class MyUserManager(BaseUserManager):
@@ -59,6 +61,9 @@ class Token(rest_framework.authtoken.models.Token):
             self.user_specific_id = int(time() * 100000)
         super().save(*args, **kwargs) # Call the "real" save() method.
 
+    def generate_key(self):
+        return b64encode(urandom(21)).decode('utf-8')
+
     class Meta:
         abstract = False
         unique_together = (('user', 'user_specific_id'),)

+ 2 - 0
test/e2e/schemas.js

@@ -60,3 +60,5 @@ exports.tokens = {
     type: "array",
     items: exports.token
 };
+
+exports.TOKEN_REGEX = /^[A-Za-z0-9+/]{28}$/

+ 4 - 4
test/e2e/spec/api_spec.js

@@ -64,7 +64,7 @@ describe("API", function () {
                 "email": email,
                 "password": password,
             }).then(function (loginResponse) {
-                expect(loginResponse.body.auth_token).to.match(/^[a-z0-9]{40}$/);
+                expect(loginResponse.body.auth_token).to.match(schemas.TOKEN_REGEX);
                 token = loginResponse.body.auth_token;
             });
         });
@@ -80,7 +80,7 @@ describe("API", function () {
                         "password": password,
                     }).then(function (loginResponse) {
                         expect(loginResponse).to.have.status(201);
-                        expect(loginResponse.body.auth_token).to.match(/^[a-z0-9]{40}$/);
+                        expect(loginResponse.body.auth_token).to.match(schemas.TOKEN_REGEX);
                         token1 = loginResponse.body.auth_token;
                         expect(token1).to.not.equal(token2);
                     }),
@@ -89,7 +89,7 @@ describe("API", function () {
                         "password": password,
                     }).then(function (loginResponse) {
                         expect(loginResponse).to.have.status(201);
-                        expect(loginResponse.body.auth_token).to.match(/^[a-z0-9]{40}$/);
+                        expect(loginResponse.body.auth_token).to.match(schemas.TOKEN_REGEX);
                         token2 = loginResponse.body.auth_token;
                         expect(token2).to.not.equal(token1);
                     })
@@ -180,7 +180,7 @@ describe("API", function () {
                     "email": email,
                     "password": password,
                 }).then(function (loginResponse) {
-                    expect(loginResponse.body.auth_token).to.match(/^[a-z0-9]{40}$/);
+                    expect(loginResponse.body.auth_token).to.match(schemas.TOKEN_REGEX);
                     token = loginResponse.body.auth_token;
                     chakram.setRequestHeader('Authorization', 'Token ' + token);
                 });

+ 2 - 1
test/e2e/spec/dyndns_spec.js

@@ -1,6 +1,7 @@
 var chakram = require("./../setup.js").chakram;
 var expect = chakram.expect;
 var itShowsUpInPdnsAs = require("./../setup.js").itShowsUpInPdnsAs;
+var schemas = require("./../schemas.js");
 
 describe("dyndns service", function () {
 
@@ -31,7 +32,7 @@ describe("dyndns service", function () {
                     "email": email,
                     "password": password,
                 }).then(function (loginResponse) {
-                    expect(loginResponse.body.auth_token).to.match(/^[a-z0-9]{40}$/);
+                    expect(loginResponse.body.auth_token).to.match(schemas.TOKEN_REGEX);
                     token = loginResponse.body.auth_token;
                     chakram.setRequestHeader('Authorization', 'Token ' + token);
                 });