Skip to content

Commit fbcfd39

Browse files
authored
feat: add dangerous::insecure_decode (#441)
* feat: add `dangerous::insecure_decode` Add `jsonwebtoken::dangerous::insecure_decode` to support decoding headers and claims with no signature validation. * chore: deprecate `insecure_disable_signature_validation` Add deprecated attribute to `Validation::insecure_disable_signature_validation`
1 parent 4ba3fce commit fbcfd39

File tree

6 files changed

+88
-0
lines changed

6 files changed

+88
-0
lines changed

src/decoding.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,23 @@ pub fn decode<T: DeserializeOwned + Clone>(
300300
Ok(TokenData { header, claims })
301301
}
302302

303+
/// Decode a JWT with NO VALIDATION
304+
///
305+
/// DANGER: This performs zero validation on the JWT
306+
pub fn insecure_decode<T: DeserializeOwned + Clone>(
307+
token: impl AsRef<[u8]>,
308+
) -> Result<TokenData<T>> {
309+
let token = token.as_ref();
310+
311+
let (_, message) = expect_two!(token.rsplitn(2, |b| *b == b'.'));
312+
let (payload, header) = expect_two!(message.rsplitn(2, |b| *b == b'.'));
313+
314+
let header = Header::from_encoded(header)?;
315+
let claims = DecodedJwtPartClaims::from_jwt_part_claims(payload)?.deserialize()?;
316+
317+
Ok(TokenData { header, claims })
318+
}
319+
303320
/// Return the correct [`JwtVerifier`] based on the `algorithm`.
304321
pub fn jwt_verifier_factory(
305322
algorithm: &Algorithm,

src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ pub use encoding::{EncodingKey, encode};
1717
pub use header::Header;
1818
pub use validation::{Validation, get_current_timestamp};
1919

20+
/// Dangerous decoding functions that should be audited and used with extreme care.
21+
pub mod dangerous {
22+
pub use super::decoding::insecure_decode;
23+
}
24+
2025
mod algorithms;
2126
/// Lower level functions, if you want to do something other than JWTs
2227
pub mod crypto;

src/validation.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,10 @@ impl Validation {
156156
/// Whether to validate the JWT cryptographic signature.
157157
/// Disabling validation is dangerous, only do it if you know what you're doing.
158158
/// With validation disabled you should not trust any of the values of the claims.
159+
#[deprecated(
160+
since = "10.1.0",
161+
note = "Use `jsonwebtoken::dangerous::insecure_decode` if you require this functionality."
162+
)]
159163
pub fn insecure_disable_signature_validation(&mut self) {
160164
self.validate_signature = false;
161165
}

tests/dangerous.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
use jsonwebtoken::{Algorithm, TokenData, dangerous::insecure_decode};
2+
use wasm_bindgen_test::wasm_bindgen_test;
3+
4+
#[derive(Debug, PartialEq, Eq, Clone, serde::Serialize, serde::Deserialize)]
5+
pub struct Claims {
6+
sub: String,
7+
aud: Vec<String>,
8+
iat: i64,
9+
exp: i64,
10+
}
11+
12+
#[test]
13+
#[wasm_bindgen_test]
14+
fn dangerous_insecure_decode_valid_jwt() {
15+
let token = "eyJhbGciOiJSUzI1NiIsImtpZCI6IkRReWk2eEFmVVRPWmhJV2R5VWtKZTBFMUJmM1VXV05QIiwidHlwIjoiSldUIn0.eyJhdWQiOlsianNvbndlYnRva2VudGVzdCJdLCJleHAiOjE3NTk4MjYyMTcsImlhdCI6MTc1OTgyNTkxNywic3ViIjoic3BpZmZlOi8vZXhhbXBsZS5vcmcvdGVzdHNlcnZpY2UifQ.1qr1zmMM1hmF-sDZupGc7sT2zGQxl1hFfaUKFWz3UGUeJfUweZfFymGR4jIOJb9ywXmfaafGQbNypaHILPWpeXT8RB7GZ7APu09ZPFvLiKBqagCVWgwhXc30giYPfTq5iNct1ejdYgB1wLxtnrsDRoD_k3EMkB58pDz4H5ZFXc_3xB9TLGw2UdaZ7AloV1yFV6OC5PdleSKchb9E_WaBlbZWLjQNSLhN-YhCRLJ4K59lmL_Z2rnR2812kan8xicyxJAzZ6k0y6K8tpKxUhT--THz2ikUk_olOwDIMfjYe9xmAk-PVvIGwHUVR6fMYv74vhdpwVJACkI2U7HVUhRFkg";
16+
17+
let TokenData { header, claims } = insecure_decode::<Claims>(token).unwrap();
18+
19+
assert_eq!(Algorithm::RS256, header.alg);
20+
assert_eq!("DQyi6xAfUTOZhIWdyUkJe0E1Bf3UWWNP".to_string(), header.kid.unwrap());
21+
assert_eq!(Some("JWT".to_string()), header.typ);
22+
23+
assert_eq!(vec!["jsonwebtokentest"], claims.aud);
24+
assert_eq!("spiffe://example.org/testservice", claims.sub);
25+
assert_eq!(1759825917, claims.iat);
26+
assert_eq!(1759826217, claims.exp);
27+
}
28+
29+
#[test]
30+
#[wasm_bindgen_test]
31+
fn dangerous_insecure_decode_invalid_sig() {
32+
let token = "eyJhbGciOiJSUzI1NiIsImtpZCI6IkRReWk2eEFmVVRPWmhJV2R5VWtKZTBFMUJmM1VXV05QIiwidHlwIjoiSldUIn0.eyJhdWQiOlsianNvbndlYnRva2VudGVzdCJdLCJleHAiOjE3NTk4MjYyMTcsImlhdCI6MTc1OTgyNTkxNywic3ViIjoic3BpZmZlOi8vZXhhbXBsZS5vcmcvdGVzdHNlcnZpY2UifQ.sig";
33+
34+
let TokenData { header, claims } = insecure_decode::<Claims>(token).unwrap();
35+
36+
assert_eq!(Algorithm::RS256, header.alg);
37+
assert_eq!("DQyi6xAfUTOZhIWdyUkJe0E1Bf3UWWNP".to_string(), header.kid.unwrap());
38+
assert_eq!(Some("JWT".to_string()), header.typ);
39+
40+
assert_eq!(vec!["jsonwebtokentest"], claims.aud);
41+
assert_eq!("spiffe://example.org/testservice", claims.sub);
42+
assert_eq!(1759825917, claims.iat);
43+
assert_eq!(1759826217, claims.exp);
44+
}
45+
46+
#[test]
47+
#[wasm_bindgen_test]
48+
fn dangerous_insecure_decode_invalid_header() {
49+
let token = "badz.eyJhdWQiOlsianNvbndlYnRva2VudGVzdCJdLCJleHAiOjE3NTk4MjYyMTcsImlhdCI6MTc1OTgyNTkxNywic3ViIjoic3BpZmZlOi8vZXhhbXBsZS5vcmcvdGVzdHNlcnZpY2UifQ.sig";
50+
51+
insecure_decode::<Claims>(token).unwrap_err();
52+
}
53+
54+
#[test]
55+
#[wasm_bindgen_test]
56+
fn dangerous_insecure_decode_invalid_claims() {
57+
let token = "eyJhbGciOiJSUzI1NiIsImtpZCI6IkRReWk2eEFmVVRPWmhJV2R5VWtKZTBFMUJmM1VXV05QIiwidHlwIjoiSldUIn0.badz.sig";
58+
59+
insecure_decode::<Claims>(token).unwrap_err();
60+
}

tests/hmac.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#![allow(deprecated)]
12
use serde::{Deserialize, Serialize};
23
use std::collections::HashMap;
34
use time::OffsetDateTime;

tests/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
mod dangerous;
12
mod ecdsa;
23
mod eddsa;
34
mod header;

0 commit comments

Comments
 (0)