Skip to content

Commit 7504a97

Browse files
committed
refactor: strengthen handling and protection of cryptographic secrets
- Add logging for errors when reading private and public key files - Immediately clear passphrase from memory after use in private key parsing - Improve type safety checks when extracting claims and token strings from Gin context - Implement method to clear sensitive cryptographic data from memory Signed-off-by: appleboy <[email protected]>
1 parent 177ca98 commit 7504a97

File tree

1 file changed

+67
-3
lines changed

1 file changed

+67
-3
lines changed

auth_jwt.go

Lines changed: 67 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package jwt
33
import (
44
"crypto/rsa"
55
"errors"
6+
"log"
67
"net/http"
78
"os"
89
"strings"
@@ -252,14 +253,23 @@ func (mw *GinJWTMiddleware) privateKey() error {
252253
var filecontent []byte
253254
filecontent, err = os.ReadFile(mw.PrivKeyFile)
254255
if err != nil {
256+
// Log detailed error for debugging but don't expose to client
257+
log.Printf("Failed to read private key file %s: %v", mw.PrivKeyFile, err)
255258
return ErrNoPrivKeyFile
256259
}
257260
keyData = filecontent
258261
}
259262

260263
if mw.PrivateKeyPassphrase != "" {
261264
var key interface{}
262-
key, err = pkcs8.ParsePKCS8PrivateKey(keyData, []byte(mw.PrivateKeyPassphrase))
265+
passphrase := []byte(mw.PrivateKeyPassphrase)
266+
key, err = pkcs8.ParsePKCS8PrivateKey(keyData, passphrase)
267+
268+
// Clear passphrase from memory immediately after use
269+
for i := range passphrase {
270+
passphrase[i] = 0
271+
}
272+
263273
if err != nil {
264274
return ErrInvalidPrivKey
265275
}
@@ -287,6 +297,8 @@ func (mw *GinJWTMiddleware) publicKey() error {
287297
} else {
288298
filecontent, err := os.ReadFile(mw.PubKeyFile)
289299
if err != nil {
300+
// Log detailed error for debugging but don't expose to client
301+
log.Printf("Failed to read public key file %s: %v", mw.PubKeyFile, err)
290302
return ErrNoPubKeyFile
291303
}
292304
keyData = filecontent
@@ -847,7 +859,12 @@ func ExtractClaims(c *gin.Context) jwt.MapClaims {
847859
return make(jwt.MapClaims)
848860
}
849861

850-
return claims.(jwt.MapClaims)
862+
mapClaims, ok := claims.(jwt.MapClaims)
863+
if !ok {
864+
return make(jwt.MapClaims)
865+
}
866+
867+
return mapClaims
851868
}
852869

853870
// ExtractClaimsFromToken help to extract the JWT claims from token
@@ -876,7 +893,12 @@ func GetToken(c *gin.Context) string {
876893
return ""
877894
}
878895

879-
return token.(string)
896+
tokenStr, ok := token.(string)
897+
if !ok {
898+
return ""
899+
}
900+
901+
return tokenStr
880902
}
881903

882904
// SetCookie help to set the token in the cookie
@@ -901,3 +923,45 @@ func (mw *GinJWTMiddleware) SetCookie(c *gin.Context, token string) {
901923
)
902924
}
903925
}
926+
927+
// ClearSensitiveData clears sensitive data from memory
928+
func (mw *GinJWTMiddleware) ClearSensitiveData() {
929+
// Clear symmetric key
930+
if mw.Key != nil {
931+
for i := range mw.Key {
932+
mw.Key[i] = 0
933+
}
934+
mw.Key = nil
935+
}
936+
937+
// Clear private key bytes
938+
if mw.PrivKeyBytes != nil {
939+
for i := range mw.PrivKeyBytes {
940+
mw.PrivKeyBytes[i] = 0
941+
}
942+
mw.PrivKeyBytes = nil
943+
}
944+
945+
// Clear public key bytes
946+
if mw.PubKeyBytes != nil {
947+
for i := range mw.PubKeyBytes {
948+
mw.PubKeyBytes[i] = 0
949+
}
950+
mw.PubKeyBytes = nil
951+
}
952+
953+
// Clear passphrase
954+
if len(mw.PrivateKeyPassphrase) > 0 {
955+
// Convert to []byte to clear, then back to string
956+
passBytes := []byte(mw.PrivateKeyPassphrase)
957+
for i := range passBytes {
958+
passBytes[i] = 0
959+
}
960+
mw.PrivateKeyPassphrase = ""
961+
}
962+
963+
// Note: RSA keys (mw.privKey, mw.pubKey) are harder to clear completely
964+
// due to Go's garbage collector, but setting to nil helps
965+
mw.privKey = nil
966+
mw.pubKey = nil
967+
}

0 commit comments

Comments
 (0)