สร้าง | การพึ่งพาอาศัยกัน |
---|---|
การใช้งาน JSON Web Tokens
สิ่งนี้ได้รับการพัฒนากับ draft-ietf-oauth-json-web-token-08
มันใช้ node-jws
$ npm install jsonwebtoken
(อะซิงโครนัส) หากมีการระบุการโทรกลับ การโทรกลับจะถูกเรียกด้วย err
หรือ JWT
(ซิงโครนัส) ส่งกลับ JsonWebToken เป็นสตริง
payload
อาจเป็นอ็อบเจ็กต์ลิเทอรัล บัฟเฟอร์ หรือสตริงที่แสดงถึง JSON ที่ถูกต้อง
โปรด ทราบ ว่า
exp
หรือการอ้างสิทธิ์อื่นใดจะถูกตั้งค่าเฉพาะเมื่อเพย์โหลดเป็นวัตถุตามตัวอักษร เพย์โหลดบัฟเฟอร์หรือสตริงจะไม่ได้รับการตรวจสอบความถูกต้องของ JSON
หาก
payload
ไม่ใช่บัฟเฟอร์หรือสตริง เพย์โหลดจะถูกบังคับเป็นสตริงโดยใช้JSON.stringify
secretOrPrivateKey
คือสตริง (เข้ารหัส utf-8), บัฟเฟอร์, อ็อบเจ็กต์ หรือ KeyObject ที่ประกอบด้วยข้อมูลลับสำหรับอัลกอริทึม HMAC หรือคีย์ส่วนตัวที่เข้ารหัส PEM สำหรับ RSA และ ECDSA ในกรณีของคีย์ส่วนตัวที่มีข้อความรหัสผ่าน สามารถใช้ออบเจ็กต์ { key, passphrase }
ได้ (ขึ้นอยู่กับเอกสารการเข้ารหัส) ในกรณีนี้ ต้องแน่ใจว่าคุณผ่านตัวเลือก algorithm
เมื่อลงนามด้วยอัลกอริธึม RSA ความยาวโมดูลัสขั้นต่ำคือ 2048 ยกเว้นเมื่อตั้งค่าตัวเลือก AllowInsecureKeySizes เป็นจริง คีย์ส่วนตัวที่มีขนาดต่ำกว่านี้จะถูกปฏิเสธโดยมีข้อผิดพลาด
options
:
algorithm
(ค่าเริ่มต้น: HS256
)expiresIn
: แสดงเป็นวินาทีหรือสตริงที่อธิบายช่วงเวลา vercel/msเช่น
60
,"2 days"
,"10h"
,"7d"
ค่าตัวเลขจะถูกตีความเป็นการนับวินาที หากคุณใช้สตริง ต้องแน่ใจว่าคุณระบุหน่วยเวลา (วัน ชั่วโมง ฯลฯ) มิฉะนั้นจะใช้หน่วยมิลลิวินาทีตามค่าเริ่มต้น ("120"
เท่ากับ"120ms"
)
notBefore
: แสดงเป็นวินาทีหรือสตริงที่อธิบายช่วงเวลา vercel/msเช่น
60
,"2 days"
,"10h"
,"7d"
ค่าตัวเลขจะถูกตีความเป็นการนับวินาที หากคุณใช้สตริง ต้องแน่ใจว่าคุณระบุหน่วยเวลา (วัน ชั่วโมง ฯลฯ) มิฉะนั้นจะใช้หน่วยมิลลิวินาทีตามค่าเริ่มต้น ("120"
เท่ากับ"120ms"
)
audience
issuer
jwtid
subject
noTimestamp
header
keyid
mutatePayload
: หากเป็นจริง ฟังก์ชันเครื่องหมายจะแก้ไขวัตถุเพย์โหลดโดยตรง สิ่งนี้มีประโยชน์หากคุณต้องการการอ้างอิงดิบไปยังเพย์โหลดหลังจากการอ้างสิทธิ์ได้ถูกนำไปใช้กับเพย์โหลดแล้ว แต่ก่อนที่จะถูกเข้ารหัสเป็นโทเค็นallowInsecureKeySizes
: ถ้าเป็นจริง อนุญาตให้ใช้คีย์ส่วนตัวที่มีโมดูลัสต่ำกว่า 2048 เพื่อใช้สำหรับ RSAallowInvalidAsymmetricKeyTypes
: หากเป็นจริง อนุญาตให้ใช้คีย์แบบอสมมาตรซึ่งไม่ตรงกับอัลกอริทึมที่ระบุ ตัวเลือกนี้มีไว้สำหรับความเข้ากันได้แบบย้อนหลังเท่านั้น และควรหลีกเลี่ยงไม่มีค่าเริ่มต้นสำหรับ
expiresIn
,notBefore
,audience
,subject
,issuer
การอ้างสิทธิ์เหล่านี้สามารถระบุในเพย์โหลดได้โดยตรงด้วยexp
,nbf
,aud
,sub
และiss
ตามลำดับ แต่คุณ ไม่สามารถ รวมไว้ในทั้งสองแห่งได้
โปรดจำไว้ว่า exp
, nbf
และ iat
เป็น NumericDate ดูการหมดอายุของโทเค็นที่เกี่ยวข้อง (การอ้างสิทธิ์ exp)
ส่วนหัวสามารถปรับแต่งได้ผ่านทางวัตถุ options.header
jwts ที่สร้างขึ้นจะรวมการอ้างสิทธิ์ iat
(ออกที่) ตามค่าเริ่มต้น เว้นแต่จะระบุ noTimestamp
หากใส่ iat
ลงในเพย์โหลด มันจะถูกใช้แทนการประทับเวลาจริงสำหรับการคำนวณสิ่งอื่นๆ เช่น exp
ที่กำหนดช่วงเวลาใน options.expiresIn
เครื่องหมายซิงโครนัสพร้อมค่าเริ่มต้น (HMAC SHA256)
var jwt = require ( 'jsonwebtoken' ) ;
var token = jwt . sign ( { foo : 'bar' } , 'shhhhh' ) ;
สัญญาณซิงโครนัสกับ RSA SHA256
// sign with RSA SHA256
var privateKey = fs . readFileSync ( 'private.key' ) ;
var token = jwt . sign ( { foo : 'bar' } , privateKey , { algorithm : 'RS256' } ) ;
ลงชื่อแบบอะซิงโครนัส
jwt . sign ( { foo : 'bar' } , privateKey , { algorithm : 'RS256' } , function ( err , token ) {
console . log ( token ) ;
} ) ;
ย้อนหลัง jwt 30 วินาที
var older_token = jwt . sign ( { foo : 'bar' , iat : Math . floor ( Date . now ( ) / 1000 ) - 30 } , 'shhhhh' ) ;
มาตรฐานสำหรับ JWT กำหนดการเรียกร้อง exp
สำหรับการหมดอายุ การหมดอายุจะแสดงเป็น NumericDate :
ค่าตัวเลข JSON ที่แสดงจำนวนวินาทีตั้งแต่ 1970-01-01T00:00:00Z UTC จนถึงวันที่/เวลา UTC ที่ระบุ โดยไม่สนใจวินาทีกระโดด ซึ่งเทียบเท่ากับคำจำกัดความ IEEE Std 1003.1, 2013 Edition [POSIX.1] "วินาทีนับตั้งแต่ยุค" ซึ่งในแต่ละวันคิดเป็น 86400 วินาทีพอดี ยกเว้นค่าที่ไม่ใช่จำนวนเต็มที่สามารถแสดงได้ ดู RFC 3339 [RFC3339] สำหรับรายละเอียดเกี่ยวกับวันที่/เวลาโดยทั่วไปและโดยเฉพาะ UTC
ซึ่งหมายความว่าช่อง exp
ควรมีจำนวนวินาทีนับตั้งแต่ยุคนั้น
การลงนามโทเค็นโดยมีเวลาหมดอายุ 1 ชั่วโมง:
jwt . sign ( {
exp : Math . floor ( Date . now ( ) / 1000 ) + ( 60 * 60 ) ,
data : 'foobar'
} , 'secret' ) ;
อีกวิธีในการสร้างโทเค็นเช่นนี้ด้วยไลบรารีนี้คือ:
jwt . sign ( {
data : 'foobar'
} , 'secret' , { expiresIn : 60 * 60 } ) ;
//or even better:
jwt . sign ( {
data : 'foobar'
} , 'secret' , { expiresIn : '1h' } ) ;
(อะซิงโครนัส) หากมีการระบุการโทรกลับ ฟังก์ชันจะดำเนินการแบบอะซิงโครนัส การโทรกลับจะถูกเรียกพร้อมกับเพย์โหลดที่ถอดรหัสแล้ว หากลายเซ็นถูกต้องและการหมดอายุ ผู้ชม หรือผู้ออกที่เป็นทางเลือกนั้นถูกต้อง ถ้าไม่เช่นนั้นจะถูกเรียกพร้อมกับข้อผิดพลาด
(ซิงโครนัส) หากไม่มีการเรียกกลับ ฟังก์ชันจะทำหน้าที่พร้อมกัน ส่งคืนเพย์โหลดที่ถอดรหัสหากลายเซ็นถูกต้องและการหมดอายุ ผู้ชม หรือผู้ออกที่เป็นตัวเลือกนั้นถูกต้อง ถ้าไม่เช่นนั้นจะทำให้เกิดข้อผิดพลาด
คำเตือน: เมื่อโทเค็นมาจากแหล่งที่ไม่น่าเชื่อถือ (เช่น อินพุตของผู้ใช้หรือคำขอจากภายนอก) เพย์โหลดที่ถอดรหัสที่ส่งคืนควรได้รับการปฏิบัติเหมือนกับอินพุตของผู้ใช้อื่น โปรดตรวจสอบให้แน่ใจว่าได้ฆ่าเชื้อและทำงานกับคุณสมบัติที่คาดหวังเท่านั้น
token
คือสตริง JsonWebToken
secretOrPublicKey
คือสตริง (เข้ารหัส utf-8) บัฟเฟอร์ หรือ KeyObject ที่ประกอบด้วยข้อมูลลับสำหรับอัลกอริทึม HMAC หรือคีย์สาธารณะที่เข้ารหัส PEM สำหรับ RSA และ ECDSA หาก jwt.verify
เรียกว่าอะซิงโครนัส secretOrPublicKey
อาจเป็นฟังก์ชันที่ควรดึงข้อมูลลับหรือพับลิกคีย์ ดูตัวอย่างโดยละเอียดด้านล่าง
ดังที่กล่าวไว้ในความคิดเห็นนี้มีไลบรารีอื่น ๆ ที่คาดหวังความลับที่เข้ารหัส base64 (ไบต์สุ่มเข้ารหัสโดยใช้ base64) หากเป็นกรณีของคุณคุณสามารถส่งผ่าน Buffer.from(secret, 'base64')
โดยการทำเช่นนี้ความลับจะถูกถอดรหัส การใช้ base64 และการตรวจสอบโทเค็นจะใช้ไบต์สุ่มดั้งเดิม
options
algorithms
: รายการสตริงที่มีชื่อของอัลกอริธึมที่อนุญาต ตัวอย่างเช่น ["HS256", "HS384"]
หากไม่ได้ระบุค่าเริ่มต้นจะถูกใช้ตามประเภทของคีย์ที่ให้ไว้
- ความลับ - ['HS256', 'HS384', 'HS512']
- อาร์เอส - ['RS256', 'RS384', 'RS512']
- อีซี - ['ES256', 'ES384', 'ES512']
- ค่าเริ่มต้น - ['RS256', 'RS384', 'RS512']
audience
: หากคุณต้องการตรวจสอบผู้ชม ( aud
) ให้ระบุค่าที่นี่ ผู้ชมสามารถตรวจสอบกับสตริง นิพจน์ทั่วไป หรือรายการสตริงและ/หรือนิพจน์ทั่วไปได้เช่น
"urn:foo"
,/urn:f[o]{2}/
,[/urn:f[o]{2}/, "urn:bar"]
complete
: ส่งคืนออบเจ็กต์ที่มีการถอดรหัส { payload, header, signature }
แทนที่จะเป็นเพียงเนื้อหาปกติของเพย์โหลดissuer
(ไม่บังคับ): สตริงหรืออาร์เรย์ของสตริงที่มีค่าที่ถูกต้องสำหรับฟิลด์ iss
jwtid
(เป็นทางเลือก): หากคุณต้องการตรวจสอบ JWT ID ( jti
) ให้ระบุค่าสตริงที่นี่ignoreExpiration
: หาก true
อย่าตรวจสอบการหมดอายุของโทเค็นignoreNotBefore
...subject
: หากคุณต้องการตรวจสอบ subject ( sub
) ให้ระบุค่าที่นี่clockTolerance
: จำนวนวินาทีที่ต้องยอมรับเมื่อตรวจสอบการอ้างสิทธิ์ nbf
และ exp
เพื่อจัดการกับความแตกต่างของนาฬิกาเล็กน้อยระหว่างเซิร์ฟเวอร์ต่างๆmaxAge
: อายุสูงสุดที่อนุญาตสำหรับโทเค็นที่ยังคงใช้งานได้ จะแสดงเป็นวินาทีหรือสตริงที่อธิบายช่วงเวลา vercel/msเช่น
1000
,"2 days"
,"10h"
,"7d"
ค่าตัวเลขจะถูกตีความเป็นการนับวินาที หากคุณใช้สตริง ต้องแน่ใจว่าคุณระบุหน่วยเวลา (วัน ชั่วโมง ฯลฯ) มิฉะนั้นจะใช้หน่วยมิลลิวินาทีตามค่าเริ่มต้น ("120"
เท่ากับ"120ms"
)
clockTimestamp
: เวลาเป็นวินาทีที่ควรใช้เป็นเวลาปัจจุบันสำหรับการเปรียบเทียบที่จำเป็นทั้งหมดnonce
: หากคุณต้องการตรวจสอบการอ้างสิทธิ์ nonce
ให้ระบุค่าสตริงที่นี่ มันถูกใช้กับ Open ID สำหรับโทเค็น ID (บันทึกการใช้งาน Open ID)allowInvalidAsymmetricKeyTypes
: หากเป็นจริง อนุญาตให้ใช้คีย์แบบอสมมาตรซึ่งไม่ตรงกับอัลกอริทึมที่ระบุ ตัวเลือกนี้มีไว้สำหรับความเข้ากันได้แบบย้อนหลังเท่านั้น และควรหลีกเลี่ยง // verify a token symmetric - synchronous
var decoded = jwt . verify ( token , 'shhhhh' ) ;
console . log ( decoded . foo ) // bar
// verify a token symmetric
jwt . verify ( token , 'shhhhh' , function ( err , decoded ) {
console . log ( decoded . foo ) // bar
} ) ;
// invalid token - synchronous
try {
var decoded = jwt . verify ( token , 'wrong-secret' ) ;
} catch ( err ) {
// err
}
// invalid token
jwt . verify ( token , 'wrong-secret' , function ( err , decoded ) {
// err
// decoded undefined
} ) ;
// verify a token asymmetric
var cert = fs . readFileSync ( 'public.pem' ) ; // get public key
jwt . verify ( token , cert , function ( err , decoded ) {
console . log ( decoded . foo ) // bar
} ) ;
// verify audience
var cert = fs . readFileSync ( 'public.pem' ) ; // get public key
jwt . verify ( token , cert , { audience : 'urn:foo' } , function ( err , decoded ) {
// if audience mismatch, err == invalid audience
} ) ;
// verify issuer
var cert = fs . readFileSync ( 'public.pem' ) ; // get public key
jwt . verify ( token , cert , { audience : 'urn:foo' , issuer : 'urn:issuer' } , function ( err , decoded ) {
// if issuer mismatch, err == invalid issuer
} ) ;
// verify jwt id
var cert = fs . readFileSync ( 'public.pem' ) ; // get public key
jwt . verify ( token , cert , { audience : 'urn:foo' , issuer : 'urn:issuer' , jwtid : 'jwtid' } , function ( err , decoded ) {
// if jwt id mismatch, err == invalid jwt id
} ) ;
// verify subject
var cert = fs . readFileSync ( 'public.pem' ) ; // get public key
jwt . verify ( token , cert , { audience : 'urn:foo' , issuer : 'urn:issuer' , jwtid : 'jwtid' , subject : 'subject' } , function ( err , decoded ) {
// if subject mismatch, err == invalid subject
} ) ;
// alg mismatch
var cert = fs . readFileSync ( 'public.pem' ) ; // get public key
jwt . verify ( token , cert , { algorithms : [ 'RS256' ] } , function ( err , payload ) {
// if token alg != RS256, err == invalid signature
} ) ;
// Verify using getKey callback
// Example uses https://github.com/auth0/node-jwks-rsa as a way to fetch the keys.
var jwksClient = require ( 'jwks-rsa' ) ;
var client = jwksClient ( {
jwksUri : 'https://sandrino.auth0.com/.well-known/jwks.json'
} ) ;
function getKey ( header , callback ) {
client . getSigningKey ( header . kid , function ( err , key ) {
var signingKey = key . publicKey || key . rsaPublicKey ;
callback ( null , signingKey ) ;
} ) ;
}
jwt . verify ( token , getKey , options , function ( err , decoded ) {
console . log ( decoded . foo ) // bar
} ) ;
(ซิงโครนัส) ส่งกลับเพย์โหลดที่ถอดรหัสโดยไม่ตรวจสอบว่าลายเซ็นถูกต้องหรือไม่
คำเตือน: สิ่งนี้จะ ไม่ ตรวจสอบว่าลายเซ็นนั้นถูกต้องหรือไม่ คุณ ไม่ ควรใช้สิ่งนี้กับข้อความที่ไม่น่าเชื่อถือ คุณน่าจะต้องการใช้
jwt.verify
แทน
คำเตือน: เมื่อโทเค็นมาจากแหล่งที่ไม่น่าเชื่อถือ (เช่น อินพุตของผู้ใช้หรือคำขอจากภายนอก) เพย์โหลดที่ถอดรหัสที่ส่งคืนควรได้รับการปฏิบัติเหมือนกับอินพุตของผู้ใช้อื่น โปรดตรวจสอบให้แน่ใจว่าได้ฆ่าเชื้อและทำงานกับคุณสมบัติที่คาดหวังเท่านั้น
token
คือสตริง JsonWebToken
options
:
json
: บังคับ JSON.parse บนเพย์โหลดแม้ว่าส่วนหัวจะไม่มี "typ":"JWT"
complete
: ส่งคืนออบเจ็กต์พร้อมเพย์โหลดและส่วนหัวที่ถอดรหัสแล้วตัวอย่าง
// get the decoded payload ignoring signature, no secretOrPrivateKey needed
var decoded = jwt . decode ( token ) ;
// get the decoded payload and header
var decoded = jwt . decode ( token , { complete : true } ) ;
console . log ( decoded . header ) ;
console . log ( decoded . payload )
ข้อผิดพลาดที่อาจเกิดขึ้นระหว่างการตรวจสอบ ข้อผิดพลาดคืออาร์กิวเมนต์แรกของการโทรกลับเพื่อยืนยัน
เกิดข้อผิดพลาดหากโทเค็นหมดอายุ
วัตถุข้อผิดพลาด:
jwt . verify ( token , 'shhhhh' , function ( err , decoded ) {
if ( err ) {
/*
err = {
name: 'TokenExpiredError',
message: 'jwt expired',
expiredAt: 1408621000
}
*/
}
} ) ;
วัตถุข้อผิดพลาด:
.
) jwt . verify ( token , 'shhhhh' , function ( err , decoded ) {
if ( err ) {
/*
err = {
name: 'JsonWebTokenError',
message: 'jwt malformed'
}
*/
}
} ) ;
โยนทิ้งหากเวลาปัจจุบันอยู่ก่อนการอ้างสิทธิ์ nbf
วัตถุข้อผิดพลาด:
jwt . verify ( token , 'shhhhh' , function ( err , decoded ) {
if ( err ) {
/*
err = {
name: 'NotBeforeError',
message: 'jwt not active',
date: 2018-10-04T16:10:44.000Z
}
*/
}
} ) ;
อาร์เรย์ของอัลกอริธึมที่รองรับ ปัจจุบันรองรับอัลกอริธึมต่อไปนี้
ค่าพารามิเตอร์ alg | ลายเซ็นดิจิทัลหรืออัลกอริทึม MAC |
---|---|
HS256 | HMAC ใช้อัลกอริทึมแฮช SHA-256 |
HS384 | HMAC ใช้อัลกอริทึมแฮช SHA-384 |
HS512 | HMAC ที่ใช้อัลกอริธึมแฮช SHA-512 |
RS256 | RSASSA-PKCS1-v1_5 โดยใช้อัลกอริทึมแฮช SHA-256 |
RS384 | RSASSA-PKCS1-v1_5 โดยใช้อัลกอริทึมแฮช SHA-384 |
RS512 | RSASSA-PKCS1-v1_5 โดยใช้อัลกอริทึมแฮช SHA-512 |
PS256 | RSASSA-PSS โดยใช้อัลกอริธึมแฮช SHA-256 (เฉพาะโหนด ^6.12.0 หรือ >=8.0.0) |
พีเอส384 | RSASSA-PSS โดยใช้อัลกอริธึมแฮช SHA-384 (เฉพาะโหนด ^6.12.0 หรือ >=8.0.0) |
PS512 | RSASSA-PSS โดยใช้อัลกอริธึมแฮช SHA-512 (เฉพาะโหนด ^6.12.0 หรือ >=8.0.0) |
อีเอส256 | ECDSA ใช้เส้นโค้ง P-256 และอัลกอริธึมแฮช SHA-256 |
อีเอส384 | ECDSA ใช้เส้นโค้ง P-384 และอัลกอริธึมแฮช SHA-384 |
ES512 | ECDSA ใช้เส้นโค้ง P-521 และอัลกอริธึมแฮช SHA-512 |
ไม่มี | ไม่มีลายเซ็นดิจิทัลหรือค่า MAC รวมอยู่ด้วย |
ก่อนอื่น เราขอแนะนำให้คุณคิดอย่างรอบคอบว่าการรีเฟรชอัตโนมัติ JWT จะไม่ทำให้เกิดช่องโหว่ใดๆ ในระบบของคุณหรือไม่
เราไม่สบายใจที่จะรวมสิ่งนี้ไว้เป็นส่วนหนึ่งของห้องสมุด อย่างไรก็ตาม คุณสามารถดูตัวอย่างนี้เพื่อแสดงให้เห็นว่าจะบรรลุผลสำเร็จได้อย่างไร นอกเหนือจากตัวอย่างนั้น ยังมีปัญหาและการขอดึงเพื่อรับความรู้เพิ่มเติมเกี่ยวกับหัวข้อนี้
หากคุณพบจุดบกพร่องหรือหากคุณมีคำขอคุณลักษณะ โปรดรายงานในส่วนปัญหาของพื้นที่เก็บข้อมูลนี้ โปรดอย่ารายงานช่องโหว่ด้านความปลอดภัยในตัวติดตามปัญหา GitHub สาธารณะ โปรแกรมการเปิดเผยข้อมูลอย่างมีความรับผิดชอบจะให้รายละเอียดขั้นตอนในการเปิดเผยประเด็นด้านความปลอดภัย
รับรองความถูกต้อง0
โครงการนี้ได้รับอนุญาตภายใต้ใบอนุญาต MIT ดูไฟล์ใบอนุญาตสำหรับข้อมูลเพิ่มเติม