tag:crieit.net,2005:https://crieit.net/tags/cookie/feed 「cookie」の記事 - Crieit Crieitでタグ「cookie」に投稿された最近の記事 2022-07-17T07:52:23+09:00 https://crieit.net/tags/cookie/feed tag:crieit.net,2005:PublicArticle/18243 2022-07-17T07:52:23+09:00 2022-07-17T07:52:23+09:00 https://crieit.net/posts/JavaScript-Cookie JavaScript: Cookieから特定要素を見つけ出す際のトリム <p>jQuery.Cookieなどのラッピングされたものを使用する場合には、なんの考慮もいらないはずです。<br /> 裸のJavaScriptでハンドリングする場合に忘れがちなのがトリムです。</p> <h2 id="サンプル"><a href="#%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB">サンプル</a></h2> <pre><code>function getCookie (key) { var cookies = document.cookie; var cookiesArray = cookies.split(';'); for (var tuple of cookiesArray){ var strArray = tuple.split('='); var str = strArray[0]; if (str.trim() == key) { // トリムしてあげましょう str = strArray[1]; return str.trim(); } } return ''; } </code></pre> <p>CやPerlなんかで書く場合には、まあ忘れることはないんですけどね。私の場合、JavaScriptの場合が特に油断しますね。<br /> トリムのオーバーヘッドなんてわずかでしょうからね、私の場合は、要らないんじゃない?と思える場合でもとりあえずトリムしますよ。</p> COOL MAGIC PRODUCTS tag:crieit.net,2005:PublicArticle/16644 2021-01-23T14:33:35+09:00 2021-01-23T14:33:35+09:00 https://crieit.net/posts/cookie-rust-actix-web Actix web で HttpOnly な Cookie を設定する <h1 id="はじめに"><a href="#%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB">はじめに</a></h1> <p>最近 Rust を勉強するため、<a target="_blank" rel="nofollow noopener" href="https://github.com/actix/actix-web">Actix web</a> で <a target="_blank" rel="nofollow noopener" href="https://github.com/nikaera/bloggimg">Bloggimg</a> という Web アプリケーションを作りました。その際、セッション管理のために Cookie を利用したのですが、その際の手順及び設定方法についてまとめておきます。</p> <p>本記事では Rust や Actix web のインストール方法については説明しません。Mac であれば <code>brew install rustup</code> して <code>rustup-init</code> した後、<code>PATH</code> に <code>$HOME/.cargo/bin</code> を追加するだけで大丈夫なはずです。詳細なインストール手順については <a target="_blank" rel="nofollow noopener" href="https://www.rust-lang.org/tools/install">公式サイト</a> をご参照ください。</p> <p>開発環境については <a target="_blank" rel="nofollow noopener" href="https://marketplace.visualstudio.com/items?itemName=rust-lang.rust">VSCode の Rust Plugin</a> がオススメです。Rustup で Rust をインストールしている場合、設定から Rustup の PATH を <code>$HOME/.cargo/bin/rustup</code> にするだけで利用可能です。設定手順の詳細は<a target="_blank" rel="nofollow noopener" href="https://takoyaking.hatenablog.com/entry/2020/01/05/180000">こちら</a>をご参照ください。</p> <h1 id="動作環境"><a href="#%E5%8B%95%E4%BD%9C%E7%92%B0%E5%A2%83">動作環境</a></h1> <ul> <li>Mac mini (M1, 2020) <ul> <li>Rust 1.49</li> <li>Actix web 3</li> </ul></li> </ul> <h1 id="Actix web で Cookie をセットする"><a href="#Actix+web+%E3%81%A7+Cookie+%E3%82%92%E3%82%BB%E3%83%83%E3%83%88%E3%81%99%E3%82%8B">Actix web で Cookie をセットする</a></h1> <p>サーバー側で Cookie を設定するため、HTTP レスポンスヘッダーに <a target="_blank" rel="nofollow noopener" href="https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Set-Cookie">Set-Cookie</a> を含める形でセッション情報をクライアントへ渡します。その際、最低でも Cookie の属性に <code>HttpOnly</code> と <code>Secure</code>、<code>SameSite=Strict</code> は設定します。実際の Cookie を設定するための Actix web でのサンプルコードは下記になります。</p> <pre><code class="rust">use std::env; use actix_web::{App, HttpServer}; use actix_web::cookie::{Cookie, SameSite}; use actix_web::{get, web, Error, HttpRequest, HttpResponse}; use serde::{Deserialize}; /// Cookie に設定するキー /// 今回は cookie_test をキーとして使用する /// const KEY: &str = "cookie_test"; /// 存在していれば、HTTP Request ヘッダーから Cookie 文字列を取得する関数 /// /// # Arguments /// * `req` - actix_web::HttpRequest /// /// # Return value /// * Option<String> - key=value; key1=value1;~ のような Cookie の文字列 /// fn get_cookie_string_from_header(req: HttpRequest) -> Option<String> { let cookie_header = req.headers().get("cookie"); if let Some(v) = cookie_header { let cookie_string = v.to_str().unwrap(); return Some(String::from(cookie_string)); } return None; } /// 存在していれば、特定のキーで Cookie に設定された値を取得するための関数 /// /// # Arguments /// * `key` - Cookie から取り出したい値のキー /// * `cookie_string` - get_cookie_string_from_header 関数で取得した Cookie の文字列 /// /// # Return value /// * Option<String> - Cookie に設定されている値を取得する /// fn get_cookie_value(key: &str, cookie_string: String) -> Option<String> { // 取得した Cookie 文字列を ; で分割してループで回す let kv: Vec<&str> = cookie_string.split(';').collect(); for c in kv { // Cookie 文字列をパースして key で指定した値とマッチしたキーが存在するかチェックする match Cookie::parse(c) { Ok(kv) => { if key == kv.name() { // key で指定した値とマッチしたキーが存在していたら、その値を取得する return Some(String::from(kv.value())); } } Err(e) => { println!("cookie parse error. -> {}", e); } } } return None; } /// 特定のキーで環境変数から値を取得するための関数 /// /// # Arguments /// * `key` - 環境変数から取り出したい値のキー /// /// # Return value /// * String - 環境変数の値を文字列として取得する /// fn get_env(key: &str) -> String { match env::var(key) { Ok(value) => return value, Err(e) => println!("ENV: ERR {:?}", e), } return String::new(); } /// 環境変数に設定された HTTPS の値が 1 か判定する /// Cookie の属性に Secure を付与するか判定するのに使用する /// /// # Return value /// * bool - Secure 属性を付与するか判定するための真偽値 /// fn is_https() -> bool { return get_env("HTTPS") == "1"; } /// Cookie に設定する値を扱う HTTP Query の定義 #[derive(Deserialize)] pub struct CookieQuery { pub value: String, } /// Cookie を設定するために用意したルート /// /// # Example /// /// 例えば GET /cookie?value=test にアクセスした場合、 /// Cookie に cookie_test=test が設定されるようになる /// #[get("/cookie")] async fn set_cookie(query: web::Query<CookieQuery>) -> Result<HttpResponse, Error> { // 設定したい Cookie を作成する // その際に Secure, HttpOnly, SameSite=Strict 属性を付与する let cookie = Cookie::build(KEY, &query.value) .secure(is_https()) .http_only(true) .same_site(SameSite::Strict) .finish(); // 作成した Cookie を HTTP Response の Set-Cookie ヘッダーに含めることで、 // HTTP Response を受け取ったクライアントに Cookie をセットさせる return Ok(HttpResponse::Ok() .header("Set-Cookie", cookie.to_string()) .body("")); } /// KEY で指定した Cookie が存在すれば、その値を返却する /// KEY で指定した Cookie が存在しなければ、空の文字列を返却する #[get("/")] async fn index(req: HttpRequest) -> Result<HttpResponse, Error> { let cookie_string = get_cookie_string_from_header(req); if let Some(s) = cookie_string { if let Some(v) = get_cookie_value(KEY, s) { return Ok(HttpResponse::Ok().body(v)); } } return Ok(HttpResponse::Ok().body("")); } #[actix_web::main] async fn main() -> std::io::Result<()> { HttpServer::new(|| { App::new() .service(set_cookie) .service(index) }) .bind("0.0.0.0:8080")? .run() .await } </code></pre> <p>ザッとインラインコメントで説明していますが、<br /> 最も重要な <code>set_cookie</code> 関数について簡単に説明します。</p> <p>Actix web には <a target="_blank" rel="nofollow noopener" href="https://docs.rs/actix-web/3.3.2/actix_web/http/struct.Cookie.html"><code>Cookie</code> クラス</a>が存在します。この <code>Cookie</code> クラスは Cookie 文字列を生成したり、パースしたりするのに役立ちます。<code>set_cookie</code> 関数では、Cookie を生成するための関数 <a target="_blank" rel="nofollow noopener" href="https://docs.rs/actix-web/3.3.2/actix_web/http/struct.Cookie.html#method.build"><code>Cookie::build</code></a> を利用しています。</p> <p><code>Cookie::build</code> 関数を利用することで、メソッドチェインで Cookie の値や属性を設定できます。<strong>作成した Cookie は <code>to_string</code> 関数を使用することで文字列として出力できます。出力した Cookie 文字列を HTTP レスポンスヘッダーに <code>Set-Cookie</code> として設定すれば Cookie を設定できます。</strong></p> <h1 id="動作検証"><a href="#%E5%8B%95%E4%BD%9C%E6%A4%9C%E8%A8%BC">動作検証</a></h1> <p>今回用意した Actix web のサンプルコードには 2つのエンドポイントを用意しました。</p> <div class="table-responsive"><table> <thead> <tr> <th>URI</th> <th>説明</th> </tr> </thead> <tbody> <tr> <td><code>GET /cookie</code></td> <td><code>value</code> クエリで HttpOnly な Cookie を設定する</td> </tr> <tr> <td><code>GET /</code></td> <td><code>GET /cookie</code> で設定した Cookie を確認する</td> </tr> </tbody> </table></div> <p><code>cargo run</code> で Actix web のサンプルを起動した後に、ブラウザで <code>http://localhost:8080/cookie?value=sample</code> にアクセスしてみます。またその際に HTTP レスポンスヘッダーを確認したいため、<a target="_blank" rel="nofollow noopener" href="https://developer.mozilla.org/ja/docs/Learn/Common_questions/What_are_browser_developer_tools">開発者ツール</a>を開いておきます。</p> <p><img src="https://i.gyazo.com/9a1cb0cf73aa001b9ad3fdf7d8ae9966.png" alt="スクリーンショット 2021-01-23 13.12.27.png" /><br /> <strong>HTTP レスポンスヘッダーに Set-Cookie が含まれていることを確認する</strong></p> <p><code>Set-Cookie</code> が含まれていることが確認できたら正常に Cookie が設定されているか確認します。</p> <p><img src="https://i.gyazo.com/a6963e1d7ec82c57b3ae8d4978e1c116.png" alt="スクリーンショット 2021-01-23 13.26.52.png" /><br /> <strong>HTTP リクエストヘッダーの Cookie に <code>cookie_test=sample</code> が存在していることを確認する</strong></p> <p><img src="https://i.gyazo.com/282473c4c235d92233929f95c25ca899.png" alt="スクリーンショット 2021-01-23 13.32.00.png" /><br /> <strong>実際にブラウザーにも Cookie が正しく設定されているか、開発者ツールで確認する</strong></p> <p>正常に Cookie がセットされていることが確認できれば作業完了です。Cookie の属性に <code>Secure</code> を設定した場合の動作検証は、環境変数に <code>HTTPS=1</code> をセットして <code>cargo run</code> で可能です。</p> <h1 id="おわりに"><a href="#%E3%81%8A%E3%82%8F%E3%82%8A%E3%81%AB">おわりに</a></h1> <p>Actix web で割と汎用的に使えそうな知識として Cookie の設定方法について、メモ的な記事を書いてみました。引き続き、Rust への理解を深めるために <a target="_blank" rel="nofollow noopener" href="https://github.com/nikaera/bloggimg">Bloggimg</a> の開発を進めながら学習を進めていきます 🧑‍🎓</p> <p><em>本記事の内容がセキュリティの観点から適切でない場合等はコメントでご指摘いただけますと幸いです。</em></p> <h1 id="参考リンク"><a href="#%E5%8F%82%E8%80%83%E3%83%AA%E3%83%B3%E3%82%AF">参考リンク</a></h1> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://www.rust-lang.org/tools/install">Install Rust - Rust Programming Language</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://marketplace.visualstudio.com/items?itemName=rust-lang.rust">Rust - Visual Studio Marketplace</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://takoyaking.hatenablog.com/entry/2020/01/05/180000">VSCodeでRustインストールしたのに「Rustup not available」が出るとき (備忘録) - TAKOYAKING’s blog</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Set-Cookie">Set-Cookie - HTTP | MDN</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://github.com/actix/actix-web">actix/actix-web: Actix Web is a powerful, pragmatic, and extremely fast web framework for Rust.</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://docs.rs/actix-web/3.3.2/actix_web/http/struct.Cookie.html">actix_web::http::Cookie - Rust</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://developer.mozilla.org/ja/docs/Learn/Common_questions/What_are_browser_developer_tools">ブラウザー開発者ツールとは? - ウェブ開発を学ぶ | MDN</a></li> </ul> nikaera tag:crieit.net,2005:PublicArticle/15651 2019-12-29T11:21:19+09:00 2019-12-29T11:21:19+09:00 https://crieit.net/posts/Nuxt-Firebase-Auth-Cookie NuxtでFirebase AuthのトークンをCookieに入れたり出したりする <p>NuxtのSSRで認証したいなと思ったら、こんな記事を見つけたので、試してみたときの備忘録。</p> <p><a target="_blank" rel="nofollow noopener" href="https://qiita.com/basho/items/acd6a17bb6e2a2f7a932#%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB">SSRモードのNuxtでのFirebase認証 - Qiita</a></p> <p>結果、UIDは取得できるけど、firebase-adminで検証が必要っぽい...</p> <h3 id="インストール"><a href="#%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB">インストール</a></h3> <p>cookieを扱うライブラリはいろいろあるけど、<br /> <a target="_blank" rel="nofollow noopener" href="https://github.com/reactivestack/cookies/tree/master/packages/universal-cookie#readme">universal-cookie</a>がよさそうだったので、これを使ってみる。</p> <pre><code class="shell">$ npm install universal-cookie jwt-decode </code></pre> <h3 id="使い方"><a href="#%E4%BD%BF%E3%81%84%E6%96%B9">使い方</a></h3> <pre><code class="typescript">import { IncomingMessage } from "http"; import firebase from "firebase import jwtDecode from "jwt-decode"; import Cookies from "universal-cookie"; const KEY_TOKEN = "access_token"; /** * firebase.Userからトークンを取得して、Cookieに保存 */ export async function setCookie(currentUser: firebase.User) { // firebase.UserからidTokenを取得 const token = await currentUser.getIdToken(true); // 新規追加するときは、引数なしでnew Cookies() const cookies = new Cookies(); // Cookieに保存 cookies.set(KEY_TOKEN, token); } /** * Cookieにあるトークンをデコードして、UIDを取得 */ export function getCookie(req: IncomingMessage) { if (process.server && process.static) return; if (!req.headers.cookie) return; // requestヘッダーのCookieを取得する場合は、引数に追加 const cookie = new Cookies(req.headers.cookie); const token = cookie.get(KEY_TOKEN); if (!token) return; // jwtDecodeでトークンをデコードする const decodedToken = jwtDecode(token); if (!decodedToken) return; return decodedToken.user_id; } </code></pre> <p>以上!!</p> <h2 id="こんなのつくってます!!"><a href="#%E3%81%93%E3%82%93%E3%81%AA%E3%81%AE%E3%81%A4%E3%81%8F%E3%81%A3%E3%81%A6%E3%81%BE%E3%81%99%21%21">こんなのつくってます!!</a></h2> <p>積読用の読書管理アプリ 『積読ハウマッチ』をリリースしました!<br /> <a target="_blank" rel="nofollow noopener" href="https://tsundoku.site">積読ハウマッチ</a>は、Nuxt.js+Firebaseで開発してます!</p> <p><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478782/572d4947-f40b-e4dc-1c9c-bc584cd2a66c.png" width="200"/></p> <p>もしよかったら、遊んでみてくださいヽ(=´▽`=)ノ</p> <p>要望・感想・アドバイスなどあれば、<br /> 公式アカウント(<a target="_blank" rel="nofollow noopener" href="https://twitter.com/MemoryLoverz">@MemoryLoverz</a>)や開発者(<a target="_blank" rel="nofollow noopener" href="https://twitter.com/kira_puka">@kira_puka</a>)まで♪</p> <h1 id="参考にしたサイト様"><a href="#%E5%8F%82%E8%80%83%E3%81%AB%E3%81%97%E3%81%9F%E3%82%B5%E3%82%A4%E3%83%88%E6%A7%98">参考にしたサイト様</a></h1> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/basho/items/acd6a17bb6e2a2f7a932#%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB">SSRモードのNuxtでのFirebase認証 - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://github.com/microcipcip/cookie-universal/tree/master/packages/cookie-universal-nuxt">cookie-universal/packages/cookie-universal-nuxt at master · microcipcip/cookie-universal</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://github.com/js-cookie/js-cookie">js-cookie/js-cookie: A simple, lightweight JavaScript API for handling browser cookies</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/S64/items/943e41f39e65dd3f4681">Vue.js / Nuxt.js で Cookies を isomorphic に扱えるライブラリを作った - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/sauzar18/items/6eb3fe0218e3cf6badbc">Nuxt.jsでCookieを使って閲覧したデータを取得する方法 - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/ooharabucyou/items/ec0163a099125e037f34#%E3%83%A6%E3%83%8B%E3%83%90%E3%83%BC%E3%82%B5%E3%83%AB%E3%81%AAcookie%E3%81%AE%E5%88%A9%E7%94%A8">Nuxt.js プロジェクトで便利だったモジュール・テクニックなど - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/shintarogit/items/794c6b97c7aa977c944e">Nuxt.js SSR で Cookieが送られない - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://logmi.jp/tech/articles/321246">Nuxt.jsを用いたプロダクト開発を通して得た知見 - ログミーTech</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://gist.github.com/isaumya/bfa2f5fc20beee897938c099762cc3e1">Nuxt JS: Keep user logged in with Firebase Auth and also fetch the necessary User data from Cloud Firestore and put it in your Vuex store if the user is already logged in before rendering the page</a></li> </ul> きらぷか@積読ハウマッチ/SSSAPIなど tag:crieit.net,2005:PublicArticle/15407 2019-09-18T23:38:34+09:00 2019-09-18T23:41:27+09:00 https://crieit.net/posts/cookie 【セキュリティ】cookieとセッション、セッションハイジャックとは <h1 id="cookieとセッション、セッションハイジャックとは"><a href="#cookie%E3%81%A8%E3%82%BB%E3%83%83%E3%82%B7%E3%83%A7%E3%83%B3%E3%80%81%E3%82%BB%E3%83%83%E3%82%B7%E3%83%A7%E3%83%B3%E3%83%8F%E3%82%A4%E3%82%B8%E3%83%A3%E3%83%83%E3%82%AF%E3%81%A8%E3%81%AF">cookieとセッション、セッションハイジャックとは</a></h1> <p><em>※あくまで個人の見解での説明であり、厳密の意味とは異なる場合があります。</em></p> <h3 id="1. cookieとは"><a href="#1.++cookie%E3%81%A8%E3%81%AF">1. cookieとは</a></h3> <p>途中まで画面に項目を入力していて、前の画面に戻らないといけないってなったときに全部やり直しっていうのはなかなかしんどい<br /> そんなあなたのためにウェブサーバとウェブブラウザ間での情報を保管してくれるのがcookie<br /> 開きなおして大量の情報が保持されてる時の安心感</p> <p>cookieを消すことができるのはウェブブラウザ側<br /> つまり見ようと思えばだれでも見られるところに情報がある<br /> 個人情報やらクレジットカード情報やらは入力面倒だろうけど、保持されないほうがいいね</p> <h3 id="2. セッションとは"><a href="#2.+%E3%82%BB%E3%83%83%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%A8%E3%81%AF">2. セッションとは</a></h3> <p>サーバが発行するのがセッション</p> <p>ウェブサーバとウェブブラウザは忍者<br /> 互いの合言葉を毎回確認しないと気が済まない<br /> サーバが番号を発行してセッションIDをつくり、ウェブブラウザ側がそのセッションIDを使っていればサーバのデータを閲覧更新削除できるやったー</p> <p>違ってたらもちろんデータに手は出せない</p> <p>でも悪い奴らはそのデータに手を出したい</p> <p>そうさセッションIDが分かれば悪さができてしまうのだ</p> <h3 id="3. セッションハイジャックとは"><a href="#3.++%E3%82%BB%E3%83%83%E3%82%B7%E3%83%A7%E3%83%B3%E3%83%8F%E3%82%A4%E3%82%B8%E3%83%A3%E3%83%83%E3%82%AF%E3%81%A8%E3%81%AF">3. セッションハイジャックとは</a></h3> <p>ハイジャックってのは、飛行機乗っ取りとかでよく聞く<br /> セッションハイジャックはサーバデータをなりすましてもってっちゃう<br /> セッションIDを推測やら盗聴やらでゲットできちゃったらデータはおしまい</p> <h3 id="4. セッションハイジャックを防ぐには?"><a href="#4.++%E3%82%BB%E3%83%83%E3%82%B7%E3%83%A7%E3%83%B3%E3%83%8F%E3%82%A4%E3%82%B8%E3%83%A3%E3%83%83%E3%82%AF%E3%82%92%E9%98%B2%E3%81%90%E3%81%AB%E3%81%AF%EF%BC%9F">4. セッションハイジャックを防ぐには?</a></h3> <p>忍者は必要<br /> ただし忍者にも複雑なセッションIDにも限界はある<br /> 門番とか関所とかも準備しとこう</p> <p>おわり</p> じゅりぽぽ