本站源代码
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

647 lines
19KB

  1. // Copyright 2012 The Gorilla Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package securecookie
  5. import (
  6. "bytes"
  7. "crypto/aes"
  8. "crypto/cipher"
  9. "crypto/hmac"
  10. "crypto/rand"
  11. "crypto/sha256"
  12. "crypto/subtle"
  13. "encoding/base64"
  14. "encoding/gob"
  15. "encoding/json"
  16. "fmt"
  17. "hash"
  18. "io"
  19. "strconv"
  20. "strings"
  21. "time"
  22. )
  23. // Error is the interface of all errors returned by functions in this library.
  24. type Error interface {
  25. error
  26. // IsUsage returns true for errors indicating the client code probably
  27. // uses this library incorrectly. For example, the client may have
  28. // failed to provide a valid hash key, or may have failed to configure
  29. // the Serializer adequately for encoding value.
  30. IsUsage() bool
  31. // IsDecode returns true for errors indicating that a cookie could not
  32. // be decoded and validated. Since cookies are usually untrusted
  33. // user-provided input, errors of this type should be expected.
  34. // Usually, the proper action is simply to reject the request.
  35. IsDecode() bool
  36. // IsInternal returns true for unexpected errors occurring in the
  37. // securecookie implementation.
  38. IsInternal() bool
  39. // Cause, if it returns a non-nil value, indicates that this error was
  40. // propagated from some underlying library. If this method returns nil,
  41. // this error was raised directly by this library.
  42. //
  43. // Cause is provided principally for debugging/logging purposes; it is
  44. // rare that application logic should perform meaningfully different
  45. // logic based on Cause. See, for example, the caveats described on
  46. // (MultiError).Cause().
  47. Cause() error
  48. }
  49. // errorType is a bitmask giving the error type(s) of an cookieError value.
  50. type errorType int
  51. const (
  52. usageError = errorType(1 << iota)
  53. decodeError
  54. internalError
  55. )
  56. type cookieError struct {
  57. typ errorType
  58. msg string
  59. cause error
  60. }
  61. func (e cookieError) IsUsage() bool { return (e.typ & usageError) != 0 }
  62. func (e cookieError) IsDecode() bool { return (e.typ & decodeError) != 0 }
  63. func (e cookieError) IsInternal() bool { return (e.typ & internalError) != 0 }
  64. func (e cookieError) Cause() error { return e.cause }
  65. func (e cookieError) Error() string {
  66. parts := []string{"securecookie: "}
  67. if e.msg == "" {
  68. parts = append(parts, "error")
  69. } else {
  70. parts = append(parts, e.msg)
  71. }
  72. if c := e.Cause(); c != nil {
  73. parts = append(parts, " - caused by: ", c.Error())
  74. }
  75. return strings.Join(parts, "")
  76. }
  77. var (
  78. errGeneratingIV = cookieError{typ: internalError, msg: "failed to generate random iv"}
  79. errNoCodecs = cookieError{typ: usageError, msg: "no codecs provided"}
  80. errHashKeyNotSet = cookieError{typ: usageError, msg: "hash key is not set"}
  81. errBlockKeyNotSet = cookieError{typ: usageError, msg: "block key is not set"}
  82. errEncodedValueTooLong = cookieError{typ: usageError, msg: "the value is too long"}
  83. errValueToDecodeTooLong = cookieError{typ: decodeError, msg: "the value is too long"}
  84. errTimestampInvalid = cookieError{typ: decodeError, msg: "invalid timestamp"}
  85. errTimestampTooNew = cookieError{typ: decodeError, msg: "timestamp is too new"}
  86. errTimestampExpired = cookieError{typ: decodeError, msg: "expired timestamp"}
  87. errDecryptionFailed = cookieError{typ: decodeError, msg: "the value could not be decrypted"}
  88. errValueNotByte = cookieError{typ: decodeError, msg: "value not a []byte."}
  89. errValueNotBytePtr = cookieError{typ: decodeError, msg: "value not a pointer to []byte."}
  90. // ErrMacInvalid indicates that cookie decoding failed because the HMAC
  91. // could not be extracted and verified. Direct use of this error
  92. // variable is deprecated; it is public only for legacy compatibility,
  93. // and may be privatized in the future, as it is rarely useful to
  94. // distinguish between this error and other Error implementations.
  95. ErrMacInvalid = cookieError{typ: decodeError, msg: "the value is not valid"}
  96. )
  97. // Codec defines an interface to encode and decode cookie values.
  98. type Codec interface {
  99. Encode(name string, value interface{}) (string, error)
  100. Decode(name, value string, dst interface{}) error
  101. }
  102. // New returns a new SecureCookie.
  103. //
  104. // hashKey is required, used to authenticate values using HMAC. Create it using
  105. // GenerateRandomKey(). It is recommended to use a key with 32 or 64 bytes.
  106. //
  107. // blockKey is optional, used to encrypt values. Create it using
  108. // GenerateRandomKey(). The key length must correspond to the block size
  109. // of the encryption algorithm. For AES, used by default, valid lengths are
  110. // 16, 24, or 32 bytes to select AES-128, AES-192, or AES-256.
  111. // The default encoder used for cookie serialization is encoding/gob.
  112. //
  113. // Note that keys created using GenerateRandomKey() are not automatically
  114. // persisted. New keys will be created when the application is restarted, and
  115. // previously issued cookies will not be able to be decoded.
  116. func New(hashKey, blockKey []byte) *SecureCookie {
  117. s := &SecureCookie{
  118. hashKey: hashKey,
  119. blockKey: blockKey,
  120. hashFunc: sha256.New,
  121. maxAge: 86400 * 30,
  122. maxLength: 4096,
  123. sz: GobEncoder{},
  124. }
  125. if hashKey == nil {
  126. s.err = errHashKeyNotSet
  127. }
  128. if blockKey != nil {
  129. s.BlockFunc(aes.NewCipher)
  130. }
  131. return s
  132. }
  133. // SecureCookie encodes and decodes authenticated and optionally encrypted
  134. // cookie values.
  135. type SecureCookie struct {
  136. hashKey []byte
  137. hashFunc func() hash.Hash
  138. blockKey []byte
  139. block cipher.Block
  140. maxLength int
  141. maxAge int64
  142. minAge int64
  143. err error
  144. sz Serializer
  145. // For testing purposes, the function that returns the current timestamp.
  146. // If not set, it will use time.Now().UTC().Unix().
  147. timeFunc func() int64
  148. }
  149. // Serializer provides an interface for providing custom serializers for cookie
  150. // values.
  151. type Serializer interface {
  152. Serialize(src interface{}) ([]byte, error)
  153. Deserialize(src []byte, dst interface{}) error
  154. }
  155. // GobEncoder encodes cookie values using encoding/gob. This is the simplest
  156. // encoder and can handle complex types via gob.Register.
  157. type GobEncoder struct{}
  158. // JSONEncoder encodes cookie values using encoding/json. Users who wish to
  159. // encode complex types need to satisfy the json.Marshaller and
  160. // json.Unmarshaller interfaces.
  161. type JSONEncoder struct{}
  162. // NopEncoder does not encode cookie values, and instead simply accepts a []byte
  163. // (as an interface{}) and returns a []byte. This is particularly useful when
  164. // you encoding an object upstream and do not wish to re-encode it.
  165. type NopEncoder struct{}
  166. // MaxLength restricts the maximum length, in bytes, for the cookie value.
  167. //
  168. // Default is 4096, which is the maximum value accepted by Internet Explorer.
  169. func (s *SecureCookie) MaxLength(value int) *SecureCookie {
  170. s.maxLength = value
  171. return s
  172. }
  173. // MaxAge restricts the maximum age, in seconds, for the cookie value.
  174. //
  175. // Default is 86400 * 30. Set it to 0 for no restriction.
  176. func (s *SecureCookie) MaxAge(value int) *SecureCookie {
  177. s.maxAge = int64(value)
  178. return s
  179. }
  180. // MinAge restricts the minimum age, in seconds, for the cookie value.
  181. //
  182. // Default is 0 (no restriction).
  183. func (s *SecureCookie) MinAge(value int) *SecureCookie {
  184. s.minAge = int64(value)
  185. return s
  186. }
  187. // HashFunc sets the hash function used to create HMAC.
  188. //
  189. // Default is crypto/sha256.New.
  190. func (s *SecureCookie) HashFunc(f func() hash.Hash) *SecureCookie {
  191. s.hashFunc = f
  192. return s
  193. }
  194. // BlockFunc sets the encryption function used to create a cipher.Block.
  195. //
  196. // Default is crypto/aes.New.
  197. func (s *SecureCookie) BlockFunc(f func([]byte) (cipher.Block, error)) *SecureCookie {
  198. if s.blockKey == nil {
  199. s.err = errBlockKeyNotSet
  200. } else if block, err := f(s.blockKey); err == nil {
  201. s.block = block
  202. } else {
  203. s.err = cookieError{cause: err, typ: usageError}
  204. }
  205. return s
  206. }
  207. // Encoding sets the encoding/serialization method for cookies.
  208. //
  209. // Default is encoding/gob. To encode special structures using encoding/gob,
  210. // they must be registered first using gob.Register().
  211. func (s *SecureCookie) SetSerializer(sz Serializer) *SecureCookie {
  212. s.sz = sz
  213. return s
  214. }
  215. // Encode encodes a cookie value.
  216. //
  217. // It serializes, optionally encrypts, signs with a message authentication code,
  218. // and finally encodes the value.
  219. //
  220. // The name argument is the cookie name. It is stored with the encoded value.
  221. // The value argument is the value to be encoded. It can be any value that can
  222. // be encoded using the currently selected serializer; see SetSerializer().
  223. //
  224. // It is the client's responsibility to ensure that value, when encoded using
  225. // the current serialization/encryption settings on s and then base64-encoded,
  226. // is shorter than the maximum permissible length.
  227. func (s *SecureCookie) Encode(name string, value interface{}) (string, error) {
  228. if s.err != nil {
  229. return "", s.err
  230. }
  231. if s.hashKey == nil {
  232. s.err = errHashKeyNotSet
  233. return "", s.err
  234. }
  235. var err error
  236. var b []byte
  237. // 1. Serialize.
  238. if b, err = s.sz.Serialize(value); err != nil {
  239. return "", cookieError{cause: err, typ: usageError}
  240. }
  241. // 2. Encrypt (optional).
  242. if s.block != nil {
  243. if b, err = encrypt(s.block, b); err != nil {
  244. return "", cookieError{cause: err, typ: usageError}
  245. }
  246. }
  247. b = encode(b)
  248. // 3. Create MAC for "name|date|value". Extra pipe to be used later.
  249. b = []byte(fmt.Sprintf("%s|%d|%s|", name, s.timestamp(), b))
  250. mac := createMac(hmac.New(s.hashFunc, s.hashKey), b[:len(b)-1])
  251. // Append mac, remove name.
  252. b = append(b, mac...)[len(name)+1:]
  253. // 4. Encode to base64.
  254. b = encode(b)
  255. // 5. Check length.
  256. if s.maxLength != 0 && len(b) > s.maxLength {
  257. return "", errEncodedValueTooLong
  258. }
  259. // Done.
  260. return string(b), nil
  261. }
  262. // Decode decodes a cookie value.
  263. //
  264. // It decodes, verifies a message authentication code, optionally decrypts and
  265. // finally deserializes the value.
  266. //
  267. // The name argument is the cookie name. It must be the same name used when
  268. // it was stored. The value argument is the encoded cookie value. The dst
  269. // argument is where the cookie will be decoded. It must be a pointer.
  270. func (s *SecureCookie) Decode(name, value string, dst interface{}) error {
  271. if s.err != nil {
  272. return s.err
  273. }
  274. if s.hashKey == nil {
  275. s.err = errHashKeyNotSet
  276. return s.err
  277. }
  278. // 1. Check length.
  279. if s.maxLength != 0 && len(value) > s.maxLength {
  280. return errValueToDecodeTooLong
  281. }
  282. // 2. Decode from base64.
  283. b, err := decode([]byte(value))
  284. if err != nil {
  285. return err
  286. }
  287. // 3. Verify MAC. Value is "date|value|mac".
  288. parts := bytes.SplitN(b, []byte("|"), 3)
  289. if len(parts) != 3 {
  290. return ErrMacInvalid
  291. }
  292. h := hmac.New(s.hashFunc, s.hashKey)
  293. b = append([]byte(name+"|"), b[:len(b)-len(parts[2])-1]...)
  294. if err = verifyMac(h, b, parts[2]); err != nil {
  295. return err
  296. }
  297. // 4. Verify date ranges.
  298. var t1 int64
  299. if t1, err = strconv.ParseInt(string(parts[0]), 10, 64); err != nil {
  300. return errTimestampInvalid
  301. }
  302. t2 := s.timestamp()
  303. if s.minAge != 0 && t1 > t2-s.minAge {
  304. return errTimestampTooNew
  305. }
  306. if s.maxAge != 0 && t1 < t2-s.maxAge {
  307. return errTimestampExpired
  308. }
  309. // 5. Decrypt (optional).
  310. b, err = decode(parts[1])
  311. if err != nil {
  312. return err
  313. }
  314. if s.block != nil {
  315. if b, err = decrypt(s.block, b); err != nil {
  316. return err
  317. }
  318. }
  319. // 6. Deserialize.
  320. if err = s.sz.Deserialize(b, dst); err != nil {
  321. return cookieError{cause: err, typ: decodeError}
  322. }
  323. // Done.
  324. return nil
  325. }
  326. // timestamp returns the current timestamp, in seconds.
  327. //
  328. // For testing purposes, the function that generates the timestamp can be
  329. // overridden. If not set, it will return time.Now().UTC().Unix().
  330. func (s *SecureCookie) timestamp() int64 {
  331. if s.timeFunc == nil {
  332. return time.Now().UTC().Unix()
  333. }
  334. return s.timeFunc()
  335. }
  336. // Authentication -------------------------------------------------------------
  337. // createMac creates a message authentication code (MAC).
  338. func createMac(h hash.Hash, value []byte) []byte {
  339. h.Write(value)
  340. return h.Sum(nil)
  341. }
  342. // verifyMac verifies that a message authentication code (MAC) is valid.
  343. func verifyMac(h hash.Hash, value []byte, mac []byte) error {
  344. mac2 := createMac(h, value)
  345. // Check that both MACs are of equal length, as subtle.ConstantTimeCompare
  346. // does not do this prior to Go 1.4.
  347. if len(mac) == len(mac2) && subtle.ConstantTimeCompare(mac, mac2) == 1 {
  348. return nil
  349. }
  350. return ErrMacInvalid
  351. }
  352. // Encryption -----------------------------------------------------------------
  353. // encrypt encrypts a value using the given block in counter mode.
  354. //
  355. // A random initialization vector (http://goo.gl/zF67k) with the length of the
  356. // block size is prepended to the resulting ciphertext.
  357. func encrypt(block cipher.Block, value []byte) ([]byte, error) {
  358. iv := GenerateRandomKey(block.BlockSize())
  359. if iv == nil {
  360. return nil, errGeneratingIV
  361. }
  362. // Encrypt it.
  363. stream := cipher.NewCTR(block, iv)
  364. stream.XORKeyStream(value, value)
  365. // Return iv + ciphertext.
  366. return append(iv, value...), nil
  367. }
  368. // decrypt decrypts a value using the given block in counter mode.
  369. //
  370. // The value to be decrypted must be prepended by a initialization vector
  371. // (http://goo.gl/zF67k) with the length of the block size.
  372. func decrypt(block cipher.Block, value []byte) ([]byte, error) {
  373. size := block.BlockSize()
  374. if len(value) > size {
  375. // Extract iv.
  376. iv := value[:size]
  377. // Extract ciphertext.
  378. value = value[size:]
  379. // Decrypt it.
  380. stream := cipher.NewCTR(block, iv)
  381. stream.XORKeyStream(value, value)
  382. return value, nil
  383. }
  384. return nil, errDecryptionFailed
  385. }
  386. // Serialization --------------------------------------------------------------
  387. // Serialize encodes a value using gob.
  388. func (e GobEncoder) Serialize(src interface{}) ([]byte, error) {
  389. buf := new(bytes.Buffer)
  390. enc := gob.NewEncoder(buf)
  391. if err := enc.Encode(src); err != nil {
  392. return nil, cookieError{cause: err, typ: usageError}
  393. }
  394. return buf.Bytes(), nil
  395. }
  396. // Deserialize decodes a value using gob.
  397. func (e GobEncoder) Deserialize(src []byte, dst interface{}) error {
  398. dec := gob.NewDecoder(bytes.NewBuffer(src))
  399. if err := dec.Decode(dst); err != nil {
  400. return cookieError{cause: err, typ: decodeError}
  401. }
  402. return nil
  403. }
  404. // Serialize encodes a value using encoding/json.
  405. func (e JSONEncoder) Serialize(src interface{}) ([]byte, error) {
  406. buf := new(bytes.Buffer)
  407. enc := json.NewEncoder(buf)
  408. if err := enc.Encode(src); err != nil {
  409. return nil, cookieError{cause: err, typ: usageError}
  410. }
  411. return buf.Bytes(), nil
  412. }
  413. // Deserialize decodes a value using encoding/json.
  414. func (e JSONEncoder) Deserialize(src []byte, dst interface{}) error {
  415. dec := json.NewDecoder(bytes.NewReader(src))
  416. if err := dec.Decode(dst); err != nil {
  417. return cookieError{cause: err, typ: decodeError}
  418. }
  419. return nil
  420. }
  421. // Serialize passes a []byte through as-is.
  422. func (e NopEncoder) Serialize(src interface{}) ([]byte, error) {
  423. if b, ok := src.([]byte); ok {
  424. return b, nil
  425. }
  426. return nil, errValueNotByte
  427. }
  428. // Deserialize passes a []byte through as-is.
  429. func (e NopEncoder) Deserialize(src []byte, dst interface{}) error {
  430. if dat, ok := dst.(*[]byte); ok {
  431. *dat = src
  432. return nil
  433. }
  434. return errValueNotBytePtr
  435. }
  436. // Encoding -------------------------------------------------------------------
  437. // encode encodes a value using base64.
  438. func encode(value []byte) []byte {
  439. encoded := make([]byte, base64.URLEncoding.EncodedLen(len(value)))
  440. base64.URLEncoding.Encode(encoded, value)
  441. return encoded
  442. }
  443. // decode decodes a cookie using base64.
  444. func decode(value []byte) ([]byte, error) {
  445. decoded := make([]byte, base64.URLEncoding.DecodedLen(len(value)))
  446. b, err := base64.URLEncoding.Decode(decoded, value)
  447. if err != nil {
  448. return nil, cookieError{cause: err, typ: decodeError, msg: "base64 decode failed"}
  449. }
  450. return decoded[:b], nil
  451. }
  452. // Helpers --------------------------------------------------------------------
  453. // GenerateRandomKey creates a random key with the given length in bytes.
  454. // On failure, returns nil.
  455. //
  456. // Callers should explicitly check for the possibility of a nil return, treat
  457. // it as a failure of the system random number generator, and not continue.
  458. func GenerateRandomKey(length int) []byte {
  459. k := make([]byte, length)
  460. if _, err := io.ReadFull(rand.Reader, k); err != nil {
  461. return nil
  462. }
  463. return k
  464. }
  465. // CodecsFromPairs returns a slice of SecureCookie instances.
  466. //
  467. // It is a convenience function to create a list of codecs for key rotation. Note
  468. // that the generated Codecs will have the default options applied: callers
  469. // should iterate over each Codec and type-assert the underlying *SecureCookie to
  470. // change these.
  471. //
  472. // Example:
  473. //
  474. // codecs := securecookie.CodecsFromPairs(
  475. // []byte("new-hash-key"),
  476. // []byte("new-block-key"),
  477. // []byte("old-hash-key"),
  478. // []byte("old-block-key"),
  479. // )
  480. //
  481. // // Modify each instance.
  482. // for _, s := range codecs {
  483. // if cookie, ok := s.(*securecookie.SecureCookie); ok {
  484. // cookie.MaxAge(86400 * 7)
  485. // cookie.SetSerializer(securecookie.JSONEncoder{})
  486. // cookie.HashFunc(sha512.New512_256)
  487. // }
  488. // }
  489. //
  490. func CodecsFromPairs(keyPairs ...[]byte) []Codec {
  491. codecs := make([]Codec, len(keyPairs)/2+len(keyPairs)%2)
  492. for i := 0; i < len(keyPairs); i += 2 {
  493. var blockKey []byte
  494. if i+1 < len(keyPairs) {
  495. blockKey = keyPairs[i+1]
  496. }
  497. codecs[i/2] = New(keyPairs[i], blockKey)
  498. }
  499. return codecs
  500. }
  501. // EncodeMulti encodes a cookie value using a group of codecs.
  502. //
  503. // The codecs are tried in order. Multiple codecs are accepted to allow
  504. // key rotation.
  505. //
  506. // On error, may return a MultiError.
  507. func EncodeMulti(name string, value interface{}, codecs ...Codec) (string, error) {
  508. if len(codecs) == 0 {
  509. return "", errNoCodecs
  510. }
  511. var errors MultiError
  512. for _, codec := range codecs {
  513. encoded, err := codec.Encode(name, value)
  514. if err == nil {
  515. return encoded, nil
  516. }
  517. errors = append(errors, err)
  518. }
  519. return "", errors
  520. }
  521. // DecodeMulti decodes a cookie value using a group of codecs.
  522. //
  523. // The codecs are tried in order. Multiple codecs are accepted to allow
  524. // key rotation.
  525. //
  526. // On error, may return a MultiError.
  527. func DecodeMulti(name string, value string, dst interface{}, codecs ...Codec) error {
  528. if len(codecs) == 0 {
  529. return errNoCodecs
  530. }
  531. var errors MultiError
  532. for _, codec := range codecs {
  533. err := codec.Decode(name, value, dst)
  534. if err == nil {
  535. return nil
  536. }
  537. errors = append(errors, err)
  538. }
  539. return errors
  540. }
  541. // MultiError groups multiple errors.
  542. type MultiError []error
  543. func (m MultiError) IsUsage() bool { return m.any(func(e Error) bool { return e.IsUsage() }) }
  544. func (m MultiError) IsDecode() bool { return m.any(func(e Error) bool { return e.IsDecode() }) }
  545. func (m MultiError) IsInternal() bool { return m.any(func(e Error) bool { return e.IsInternal() }) }
  546. // Cause returns nil for MultiError; there is no unique underlying cause in the
  547. // general case.
  548. //
  549. // Note: we could conceivably return a non-nil Cause only when there is exactly
  550. // one child error with a Cause. However, it would be brittle for client code
  551. // to rely on the arity of causes inside a MultiError, so we have opted not to
  552. // provide this functionality. Clients which really wish to access the Causes
  553. // of the underlying errors are free to iterate through the errors themselves.
  554. func (m MultiError) Cause() error { return nil }
  555. func (m MultiError) Error() string {
  556. s, n := "", 0
  557. for _, e := range m {
  558. if e != nil {
  559. if n == 0 {
  560. s = e.Error()
  561. }
  562. n++
  563. }
  564. }
  565. switch n {
  566. case 0:
  567. return "(0 errors)"
  568. case 1:
  569. return s
  570. case 2:
  571. return s + " (and 1 other error)"
  572. }
  573. return fmt.Sprintf("%s (and %d other errors)", s, n-1)
  574. }
  575. // any returns true if any element of m is an Error for which pred returns true.
  576. func (m MultiError) any(pred func(Error) bool) bool {
  577. for _, e := range m {
  578. if ourErr, ok := e.(Error); ok && pred(ourErr) {
  579. return true
  580. }
  581. }
  582. return false
  583. }
上海开阖软件有限公司 沪ICP备12045867号-1