【问题标题】:How to add expiry to JWE?如何为 JWE 添加到期时间?
【发布时间】:2020-04-11 16:12:54
【问题描述】:

我正在尝试将到期时间添加到我使用 jwcrypto 库以下列方式生成的 JWE

from jwcrypto import jwe, jwk, jwt
from datetime import datetime, timedelta
import time

# create JWK from existing key
jwk_str = '{"k":"29Js2yXM6P_4v9K1mHDlYVHw8Xvm_GEhvMTvKTRLRzY","kty":"oct"}'
jwk_key = jwk.JWK.from_json(jwk_str)

# calculate expiry time
d = datetime.now() + timedelta(seconds=5)
epoch = datetime.utcfromtimestamp(0)
total_seconds =  (d - epoch).total_seconds()
# Add exp to the claims
claims={"exp": total_seconds, "sub": "Some random payload"}
print(claims)
jwttoken = jwt.JWT(header={"alg": "A256KW", "enc": "A256CBC-HS512"}, claims=claims)
jwttoken.make_encrypted_token(jwk_key)
jwetokenstr = jwttoken.serialize()
print(jwetokenstr)

# wait for 10 seconds to cross the expiry time
time.sleep(10)

jwttoken = jwt.JWT()
jwttoken.deserialize(token, jwk_key) # Ideally this line should fail as expiry is reached but it doesn't
print(jwttoken.claims)

我正在获取有效负载,但未读取到期声明并且在到期时不会失败。 我做错了什么?

【问题讨论】:

  • 请显示有效载荷中 exp 的确切值。我不知道这个库,但通常到期不会在 exp 中写入的同一秒失败。它甚至可能需要 5 分钟,具体取决于时钟偏差设置
  • @jps :是的,我认为有 60 秒的默认余地

标签: python jwt jwe jwcrypto


【解决方案1】:

这最终会减少为日期时间操作错误。

JSON Web 令牌的 exp 声明应填写自到期时间的纪元以来的秒数。

datetime.now() 返回一个本地时间(不是 UTC 时间)datetime.datetime 对象。然后上面的代码继续从 0 纪元时间的 UTC 时间 datetime.datetime 对象中减去这个本地时间 datetime.datetime 对象,并评估这两者之间的总秒数以确定到期时间。 然而,因为这是比较 本地时间 日期时间和 UTC 时间 日期时间,所以这里的秒数实际上偏离纪元时间您的本地时区与 UTC 的差异的常数因素。

例如,如果我住在一个时间比 UTC 早 5 小时的地方,我实际上将使用一个纪元时间,该纪元时间是我想要的真实纪元时间的 5 * 60 * 60 秒,用于此代码的到期。

相反,您可以简单地使用round(time.time()) + x,其中x 是JWT 未来应该到期的秒数。 time.time() 从纪元返回秒数(但作为浮点数,因此您需要四舍五入)。

例如:

from jwcrypto import jwe, jwk, jwt
from datetime import datetime, timedelta
import time

jwk_str = '{"k":"29Js2yXM6P_4v9K1mHDlYVHw8Xvm_GEhvMTvKTRLRzY","kty":"oct"}'
jwk_key = jwk.JWK.from_json(jwk_str)

jwt_valid_seconds = 3
expiry_time = round(time.time()) + jwt_valid_seconds
claims={"exp": expiry_time, "sub": "Some random payload"}
jwttoken = jwt.JWT(header={"alg": "A256KW", "enc": "A256CBC-HS512"}, claims=claims)
jwttoken.make_encrypted_token(jwk_key)
jwetokenstr = jwttoken.serialize()

jwttoken2 = jwt.JWT()
jwttoken2.deserialize(jwetokenstr, jwk_key)
print('This should succeed because we are deserializing immediately before the JWT has expired:')
print(jwttoken2.claims)

# Wait for the JWT to expire, and then extra time for the leeway.
leeway = 60
time.sleep(leeway + jwt_valid_seconds + 1)

jwttoken2 = jwt.JWT()
print('\nThis should fail due to the JWT expiring:')
jwttoken2.deserialize(jwetokenstr, jwk_key)

给出输出

(env) $ python jwe_expiry.py
This should succeed because we are deserializing immediately before the JWT has expired:
{"exp":1576737332,"sub":"Some random payload"}

This should fail due to the JWT expiring:
Traceback (most recent call last):
  File "jwe_expiry.py", line 26, in <module>
    jwttoken2.deserialize(jwetokenstr, jwk_key)
  File "... python3.7/site-packages/jwcrypto/jwt.py", line 493, in deserialize
    self._check_provided_claims()
  File "... python3.7/site-packages/jwcrypto/jwt.py", line 370, in _check_provided_claims
    self._check_default_claims(claims)
  File "... python3.7/site-packages/jwcrypto/jwt.py", line 351, in _check_default_claims
    self._check_exp(claims['exp'], time.time(), self._leeway)
  File "... python3.7/site-packages/jwcrypto/jwt.py", line 333, in _check_exp
    claim, limit, leeway))
jwcrypto.jwt.JWTExpired: Expired at 1576737332, time: 1576737392(leeway: 60)

【讨论】:

  • 感谢 Max L 这对我有用。想知道如何在 golang 中使用 gopkg.in/square/go-jose.v2 解析和验证此声明
猜你喜欢
  • 2019-12-24
  • 2017-04-10
  • 1970-01-01
  • 1970-01-01
  • 2023-03-31
  • 1970-01-01
  • 1970-01-01
  • 2016-11-17
  • 2015-09-21
相关资源
最近更新 更多