Skip to content
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 11 additions & 21 deletions snippets/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import (
"context"
"encoding/base64"
"encoding/json"
"io/ioutil"
"log"
"net/http"
"time"
Expand Down Expand Up @@ -631,8 +630,10 @@ func loginHandler(client *auth.Client) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// Get the ID token sent by the client
defer r.Body.Close()
idToken, err := getIDTokenFromBody(r)
if err != nil {
var requestBody struct {
IDToken string `json:"idToken"`
}
if err := json.NewDecoder(r.Body).Decode(&requestBody); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
Comment on lines +633 to 639

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To prevent potential Denial of Service (DoS) attacks via resource exhaustion, it is highly recommended to limit the request body size using http.MaxBytesReader before decoding. Additionally, we should validate that the idToken is not empty to avoid unnecessary downstream processing and return a 400 Bad Request instead of a 500 Internal Server Error when the token is missing.

Suggested change
var requestBody struct {
IDToken string `json:"idToken"`
}
if err := json.NewDecoder(r.Body).Decode(&requestBody); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
r.Body = http.MaxBytesReader(w, r.Body, 1048576)
var requestBody struct {
IDToken string `json:"idToken"`
}
if err := json.NewDecoder(r.Body).Decode(&requestBody); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
if requestBody.IDToken == "" {
http.Error(w, "idToken is required", http.StatusBadRequest)
return
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since these are just for snippets I think this is a bit much. These types of optimizations should be left to the developer.

Expand All @@ -644,7 +645,7 @@ func loginHandler(client *auth.Client) http.HandlerFunc {
// The session cookie will have the same claims as the ID token.
// To only allow session cookie setting on recent sign-in, auth_time in ID token
// can be checked to ensure user was recently signed in before creating a session cookie.
cookie, err := client.SessionCookie(r.Context(), idToken, expiresIn)
cookie, err := client.SessionCookie(r.Context(), requestBody.IDToken, expiresIn)
if err != nil {
http.Error(w, "Failed to create a session cookie", http.StatusInternalServerError)
return
Expand All @@ -668,13 +669,15 @@ func loginWithAuthTimeCheckHandler(client *auth.Client) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// Get the ID token sent by the client
defer r.Body.Close()
idToken, err := getIDTokenFromBody(r)
if err != nil {
var requestBody struct {
IDToken string `json:"idToken"`
}
if err := json.NewDecoder(r.Body).Decode(&requestBody); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
Comment on lines +672 to 678

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To prevent potential Denial of Service (DoS) attacks via resource exhaustion, it is highly recommended to limit the request body size using http.MaxBytesReader before decoding. Additionally, we should validate that the idToken is not empty to avoid unnecessary downstream processing and return a 400 Bad Request instead of a 401 Unauthorized when the token is missing.

		r.Body = http.MaxBytesReader(w, r.Body, 1048576)
		var requestBody struct {
			IDToken string `json:"idToken"`
		}
		if err := json.NewDecoder(r.Body).Decode(&requestBody); err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}
		if requestBody.IDToken == "" {
			http.Error(w, "idToken is required", http.StatusBadRequest)
			return
		}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above.


decoded, err := client.VerifyIDToken(r.Context(), idToken)
decoded, err := client.VerifyIDToken(r.Context(), requestBody.IDToken)
if err != nil {
http.Error(w, "Invalid ID token", http.StatusUnauthorized)
return
Expand All @@ -686,7 +689,7 @@ func loginWithAuthTimeCheckHandler(client *auth.Client) http.HandlerFunc {
}

expiresIn := time.Hour * 24 * 5
cookie, err := client.SessionCookie(r.Context(), idToken, expiresIn)
cookie, err := client.SessionCookie(r.Context(), requestBody.IDToken, expiresIn)
if err != nil {
http.Error(w, "Failed to create a session cookie", http.StatusInternalServerError)
return
Expand Down Expand Up @@ -808,19 +811,6 @@ func sessionLogoutHandlerWithRevocation(client *auth.Client) http.HandlerFunc {
// [END session_clear_and_revoke]
}

func getIDTokenFromBody(r *http.Request) (string, error) {
b, err := ioutil.ReadAll(r.Body)
if err != nil {
return "", err
}

var parsedBody struct {
IDToken string `json:"idToken"`
}
err = json.Unmarshal(b, &parsedBody)
return parsedBody.IDToken, err
}

func newActionCodeSettings() *auth.ActionCodeSettings {
// [START init_action_code_settings]
actionCodeSettings := &auth.ActionCodeSettings{
Expand Down