Open7
echo・認証まわり

認証
- セッションパターン
- jwtパターン
- csrf
- ドメイン
- SSO(シングルサインオンの場合)
echo

セッションでの認証
- ユーザーがログイン情報(ID/パスワード)を送信
- サーバーが認証に成功
- ランダムなセッションIDを生成
- セッションID と user_id をサーバー側(DB/Redis)に保存
5. DBには、セッションIDをハッシュ化して保存 - セッションID をクライアントに Set-Cookie で返す
- クライアントは以降のリクエストで Cookie にセッションIDを含めて送信
- サーバーは受け取ったセッションIDから user_id を特定し認証を通す
9. 受け取ったセッションIDをハッシュ化してDB検索
// Cookie から「生の session_id(例: abc123xyz)」を取得
rawSessionID := getCookie(c.Request())
// 同じ方法でハッシュ化して DB のキーに使う
hashed := hashSessionID(rawSessionID)
// DB で user_id を検索
userID := db.GetUserIDBySessionHash(hashed)

実装参考
jwt
- ユーザーがログイン情報(ID/パスワード)を送信
- サーバーが認証に成功
- user_id や exp(有効期限)などを含む JWT を生成し、署名付きで発行
- JWT をクライアントにレスポンスで返す(Set-Cookie や JSON などで)
- クライアントは以降のリクエストで JWT を Authorization ヘッダーに含めて送信
- サーバーは署名を検証してトークンが改ざんされていないかチェック
- トークン内の user_id などの情報を使って認証を通す(サーバーは状態を保持しない)
サンプルコード
- token作成
- 共通鍵なので、鍵は1つしかない
- secret managerなどで管理されているはず
- NewWithClaims
- アルゴリズムの指定して、データを作成
- tokenを作成
- SignedStringメソッド、署名できる
- base64の文字列, errorを返却
- SignedStringメソッド、署名できる
- 共通鍵なので、鍵は1つしかない
- token parse
- jwt.Parse
- tokenを受け取り、SigningMethodHS256を指定
- secretも指定 hmacSampleSecret
- parsedToken.Claims (interface型)を返却する
- jwt.Parse
package main
import (
"fmt"
"time"
"github.com/golang-jwt/jwt/v5"
)
// トークン作成
// https://pkg.go.dev/github.com/golang-jwt/jwt/v5#example-New-Hmac
// トークン パース
// https://pkg.go.dev/github.com/golang-jwt/jwt/v5#example-Parse-Hmac
func main() {
// 共通鍵方式
// secrer managerなどで暗号化されてることが多い
hmacSampleSecret := []byte("your-secret")
// HS256 = HMAC + SHA-256
// HMAC 共通化ぎ方式
// SHA-256 署名方式 サーバーサイドだけで完結できる
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"foo": "bar",
"nbf": time.Date(2025, 06, 16, 12, 0, 0, 0, time.UTC).Unix(),
})
fmt.Println("token", token)
tokenString, err := token.SignedString(hmacSampleSecret)
fmt.Println(tokenString, err)
// トークンをパース
parsedToken, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
// hmacSampleSecret is a []byte containing your secret, e.g. []byte("my_secret_key")
return hmacSampleSecret, nil
}, jwt.WithValidMethods([]string{jwt.SigningMethodHS256.Alg()}))
fmt.Println("")
fmt.Println("parsedToken", parsedToken)
fmt.Println("parsedToken.Claims", parsedToken.Claims)
if claims, ok := parsedToken.Claims.(jwt.MapClaims); ok {
fmt.Println(claims)
fmt.Println(claims["foo"], claims["nbf"])
} else {
fmt.Println(err)
}
}

認証まわりで必要な知識
認証まわりで理解必要な知識
- same site オリジン
cookieが送れる制限の設定
strit , lax , none - cookieの設定
http only true => 自動送信
http only false => jsからも取れる => csrfで
3. ⭐️ブラウザからクッキーにjsでアクセスする仕様
同じドメインから送られたcookieでないとjsでcookieは取れない
-
csrf
-
認証を送る時
- cookieで
- リクエストヘッダーで
- 手動で authentication
- cors
ブラウザが他のオリジンのAPIにリクエストをアクセスして良いかサーバーに聞いて判断する
- サーバー側で、Access-Control-Allow-Originの設定をする

csrf token && jwtの運用一例
14.24分
- 前提
- ⭐️/get csrfはcorsのホワイトリストで制限してるのでトークを攻撃者は保持できない
- ホワイトリスト、正規のサイトのipアドレスしかリクエストを受けつえないとか
- 対象リクエストは、更新系、POST,PUT,DELETE
- ⭐️/get csrfはcorsのホワイトリストで制限してるのでトークを攻撃者は保持できない
- フロー
- ロードされるたびに、csrfトークンを発行
- トークンはjsonで
- axiosなどのheaderにセットする。
- 都度初期化されるので、セットすれば送れる
- axiosなどのheaderにセットする。
- トークン発行のsecretはhttp onlyで
- トークンはjsonで
- api側へリクエスト
- credentials trueで secretを送る
- headerにはセットcsrdをセットしてるので送れる
- ロードされるたびに、csrfトークンを発行
- jwt
- ログインしたら access tokenを http onlyで返却
- リクエストのたびに、署名チェックで認証をOKとする
- sessionや contextにユーザーidなどをセットする
- ⭐️これだけだと cookie自動付与でなりすましができてしまう

ドメイン
- オリジン
- スキーム + ドメイン + ポート
- ブラウザはオリジン単位でセキュリティを管理する
- サブドメインは別のオリジン扱いになることが多い

echo
- go echo
- go api 技術書店 go中級者に含まれるかも
- [] ミドルウェアの使い方
- ロガー zerolog
- work/tracking_price/backend_app
- バリデーション
- work/tracking_price/backend_app
- [] context
- [] csrf
- [] errorhadler
- ロガー zerolog