入力をバリデーション・サニタイズしなかった場合、どのようにXSSを実行できるか試したときのメモ。 HTMLインジェクションからのXSSをお試し。 ブラウザはfirefoxを使用。 やったこと概要 安全でないsinkを使ってユーザーの入力値をページに反映する。 入力をページに反映させるfunctionをsinkと呼ぶ。 入力をページに反映させる場合は、安全なsink(=危ないデータをサニタイズしてくれる・文字列として扱ってくれるsink)を使用するべき。 安全なsinkは以下。 https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html#safe-sinks 安全・安全じゃないものの例 textContentは安全(値を文字列として扱ってくれる)だが、innerHTMLは安全ではない。 (innerHTMLは<script>タグのスクリプトを実行しない。しかし、<object>タグなどのスクリプトは実行されてしまうので、安全ではない。) XSSできちゃうコード例(innerHTMLを使った場合) innerHTMLをつかってページへ入力値を反映し、スクリプトを埋め込む。 index.html <div class="input-area"> <input id="input" value> <button onclick="onSubmitButtonClick()">Submit</button> </div> <div class="message-area"> <p id="message">Enter your name</p> </div> <script src="./main.js"></script> main.js const setMessage = (message) => { // 表示するメッセージを設定 // 悪意のある入力に含まれるスクリプト実行を再現するため、入力制限・サニタイズせず、innerHTMLへ入力値を設定してしまった体で const p = document.getElementById("message"); p.innerHTML = "hello " + message + "!"; } const onSubmitButtonClick = () => { const input = document.getElementById("input"); // 入力内容を保存し、メッセージとエリアに入力内容を表示する localStorage....
Next: routingとlayout
デフォルトのファイル配置や命名を整理していたところ、routingが効かなくなったり、layoutが存在しないと怒られたりしたので調べてみたことのメモ。 参考: https://nextjs.org/docs/app/building-your-application/routing/pages-and-layouts NextのRouter Next.js uses a file-system based router app(Pages Routerの場合はpages)ディレクトリ配下のディレクトリ構造がrouteになる。 ディレクトリ名、ファイル名がrouteへ反映される。 これを知って以下の疑問が出てきた。 ディレクトリ配下にページ以外のもの(ページ内で使うコンポーネントなど)を配置していると、意図しないrouteが作られたりするかもしれないからやめたほうがいい? appまたはpagesディレクトリ配下にページ以外のものを置かないほうがよいか AppRouter, Pages Routerにより異なる。 App Routerの場合、意図しないrouteが作られるような事故は防がれる仕組みになっているので、置いてもよい。 Pages Routerの場合はそうではないので、pagesディレクトリ配下にページ以外のものを置かないほうがよい。 App Routerの場合、page.jsや、route.jsという名前のファイルに対してのみrouting可能。 (僕が実装していた際は、この規則に違反していたためroutingが効かなくなり、404エラーが出た。) 参考: https://nextjs.org/docs/app/building-your-application/routing/colocation#safe-colocation-by-default Layout ページへレイアウトを適用するためのファイル。 App Routerの場合、appディレクトリ配下にRoot Layoutが必要。 page.jsに対応するLayout(Nesting Layouts)を個別定義することもできる。 Nesting Layoutsは、上位ディレクトリに定義されたlayout.js内部にネストする形で適用される。 以下、Root Layout, Nesting Layoutsを用意した場合のディレクトリ、ファイル配置の例 app layout.js (Root Layout) dashboard layout.js (dashboard用のNesting Layout) page.js (app/layout.jsを適用した上で、app/dashboard/layout.jsを適用) home page.js (app/layout.jsを適用) (僕が実装していた際は、Root Layoutがなく、Nesting Layoutsもなかったため、以下のエラーが出た。)...
TypeScriptのenumがちょっと改善されていた
TypeScriptのEnumが型安全になっていた。 TypeScriptでEnumを使うのが良くないといわれている理由の確認中に見つけたのでメモ。 ここを使って動作確認をした。 transpile結果も確認できるので便利。 https://www.typescriptlang.org/play エラー 以下のコードを書いてみたところtypeエラーが出た。 バージョンアップでエラーが出るように修正された? Enumの型安全を検証するコード enum FruitEnum { Apple = 0, Orange = 1 } const fruit: FruitEnum = 6; エラーメッセージ Type ‘6’ is not assignable to type ‘FruitEnum’.(2322) いつからこうなった? TypeScript 5.0で修正された。 https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-0.html#all-enums-are-union-enums 備忘: Enum使うか、それ以外の手段を使うか 型安全になったからEnum使っても問題ないのか、それ以外の手段を使うべきなのかを調べてみた。 Enum, Const Enum, Unionをtranspile前後で比較して調査。 Enumは即時関数を使った形にtranspileされるので、Tree Shakingで使ってないコードを振り落とせないデメリットがある。 Const Enumか、Unionを使うのが良いかも。 Const EnumにはBabelでtranspileできない等のデメリットがあるらしいが未検証。 Enum transpile前 enum FruitEnum { Apple, Orange } const fruit: FruitEnum = FruitEnum.Apple; transpile後 var FruitEnum; (function (FruitEnum) { FruitEnum[FruitEnum["Apple"] = 0] = "Apple"; FruitEnum[FruitEnum["Orange"] = 1] = "Orange"; })(FruitEnum || (FruitEnum = {})); const fruit = FruitEnum....
Componentへパラメータを渡すとエラー
Componentへパラメータを渡せなかったときの原因と解決方法 エラー発生時の実装 タスクの一覧を引数にとってタスクリストを作成するコンポーネントを定義し、タスクの一覧を渡そうとしていた。 taskItems.jsx export const TaskItems = (tasks: Task[]) => { const taskElements = tasks.map(t => { return <div className="task" key={t.id}></div> }) return (<div className="taskList">{taskElements}</div>) } home.jsx export default function Home() { const tasks: Task[] = [ // 略 ] return ( <main> <TaskItems tasks={tasks}></TaskItems> </main> ) } エラー Typeエラーが出た。 Type ‘{ tasks: Task[]; }’ is not assignable to type ‘IntrinsicAttributes & Task[]’. Property ‘tasks’ does not exist on type ‘IntrinsicAttributes & Task[]'....
React: i18nextで多言語対応
Reactで多言語対応をしたときの手順メモ 言語はブラウザに設定されたものを利用する前提 使うもの https://www.i18next.com/ https://github.com/i18next/i18next-browser-languageDetector/tree/master i18next-browser-languagedetectorでブラウザの言語を扱えるようになる 1. インストール npm install react-i18next i18next i18next-browser-languagedetector –save 2. 設定 i18n用ファイルを用意し、多言語用リソースを扱うための諸々を設定 以下のファイルを追加 i18n.ts import i18n from "i18next"; import LanguageDetector from 'i18next-browser-languagedetector'; import { initReactI18next } from "react-i18next"; const resources = { ja: { translation: { "Title": "ホームページ", } }, en: { translation: { "Title": "Home Page", } } }; i18n.use(initReactI18next) .use(LanguageDetector) .init({ // lng: 'en' <- LanguageDetectorが機能しないのでこの設定は削除 resources, fallbackLng: 'en', supportedLngs: ['en', 'ja'], interpolation: { escapeValue: false }, detection: { // navigatorの優先度を上げる order: ['navigator'], // デフォルトの設定だとlocalStorage, cookieにcacheするようになっている。 // ブラウザの設定を参照したいので削除 caches: [] } }) export default i18n; 3....
Widening
Widening ReactでコンポーネントをスタイリングしていたらTypescript関連のエラーがでたのでメモ。 以下のようなコードを書いた const Component = () => { const divStyle = { display: "flex", flexDirection: "row", }; return ( <div style={divStyle}></div> ); } 出てきたエラー Type ‘{ display: string; flexDirection: string; }’ is not assignable to type ‘Properties<string | number, string & {}>’. Types of property ‘flexDirection’ are incompatible. Type ‘string’ is not assignable to type ‘FlexDirection | undefined’.ts(2322) FlexDirection型を設定すべきところ、“row"がstring型になってしまっていた (TypescriptのWideningによるもの) const assertionでWideningを抑制して解決 以下のコードに修正 const Component = () => { const divStyle = { display: "flex", flexDirection: "row" as const, // const assertion }; return ( <div style={divStyle}></div> ); }
Hello
テストページ aaa a b c abcde interface A { prop: string; } var a: A = { prop: "a" }; alert(a);