N予備校:プログラミング入門 Webアプリコースを学習する42

序文

N予備校のプログラミング入門 Webアプリコース42日目。
XSS対策。読み方忘れた。

f:id:yjkym:20180222142414p:plain

GitHub

github.com

客観的成果

  • N予備校 プログラミング入門 Webアプリ
    • 第3章 サーバーサイドプログラミング入門

(学習時間:2.5時間)

学習内容

  • XSS脆弱性について
  • 意図的にXSS脆弱性を攻撃する方法
  • JavaScript : onloadイベントの使い方
  • JavaScript : getElementsByTagName()関数の使い方
  • JavaScript : innerHTMLプロパティの使い方
  • XSS脆弱性対策について
  • リグレッションについて
  • jade : jadeテンプレート内にCSSを記載する方法
  • HTML : style属性の使い方
  • CSS : white-spaceプロパティの使い方
  • JavaScript : indexOf()関数の使い方

個人的Tips(備忘録)

  • XSSはクロスサイト・スクリプティングの略
  • XSS脆弱性とはWebサービスの外部からの入力で表示が変化する機能において、意図しない HTML、JavaScriptCSS の変更ができる脆弱性
  • <script>window.onload=function(){document.getElementsByTagName('h2')[0].innerHTML='新規投稿<small>(本名を入力しても自動的に除去されます)</small>';}</script>
    XSS脆弱性をついた攻撃の例
  • //- HTMLタグを認識させる
    //- p!= post.content 
    jadeでこんな風にHTMLタグを認識させるのは危険。
    むしろ思いつかねーよこんな方法。
  • コードを修正することによって本来あった機能が失われることを、リグレッション(regression)という。regret(後悔)ではない。
  • //- CSSスタイルを適用して改行を反映させる
    p(style="white-space:pre;") #{post.content}
    HTMLタグにstyle属性を適用してwhite-space:preを設定することで改行を反映させることができる。
    他にwhite-space:normalで改行やタブを半角スペースに変換できたりする
  • XSS脆弱性に対策をしたtest.jsの実装例。node test.jsで実行する。
    // 厳格モード
    'use strict';
    // 'jade'モジュール呼び出し
    const jade = require('jade');
    // 'assert'モジュール呼び出し(テスト用モジュール)
    const assert = require('assert');

    // jade のテンプレートにおける XSS 脆弱性のテスト
    // テスト用投稿のユーザー名
    let username = 'guest1';
    // テスト用投稿データを格納する配列
    let posts = [];
    // テスト用の投稿データのオブジェクト
    // HTMLタグがエスケープされることを確認するテスト投稿
    let testpost = {
    id: 1,
    content: '<script>alert(\'test\');</script>',
    postedBy: 'guest1',
    trackingCookie: 1,
    createdAt: new Date(),
    updatedAt: new Date()
    }
    // テスト用の投稿データを配列に格納する
    posts.push(testpost);
    // 投稿データをjadeテンプレートを適用してHTMに変換する
    const html = jade.renderFile('./views/posts.jade', {
    posts: posts,
    user: username
    });

    // スクリプトタグがエスケープされて含まれていることをチェック
    let result = html.indexOf('&lt;script&gt;alert(\'test\');&lt;/script&gt;')
    // indexOf()の結果が正であればOK
    assert(result > 0);

    console.log('テストが正常に完了しました');
  • 半角スペースはURLエンコードで?+文字に変換されるので、反映させるためにreplaceなりなんなりしてやる必要がある

感想

おなじみXSS対策。Railsとかだとサニタイズしてやるのが王道の対策なのかな。

シンプルなサイトなら問題は出ないだろうけど、複雑な構成のサイトになった場合、XSS対策のし忘れがないという保証はどういうふうにすればいいのだろうか。
いくつか方法は思いつくけれど、王道のパターンが知りたい。

カロリーメイトください。 

N予備校:プログラミング入門 Webアプリコースを学習する41

序文

N予備校のプログラミング入門 Webアプリコース41日目。
掲示板の実装は終わったようで、今日から脆弱性対策。

f:id:yjkym:20180221205919p:plain

GitHub

github.com

客観的成果

  • N予備校 プログラミング入門 Webアプリ
    • 第3章 サーバーサイドプログラミング入門

(学習時間:2.5時間)

学習内容

  • 脆弱性について
  • OSコマンド・インジェクションについて
  • child_processモジュール、child_process.execSync関数の使い方

個人的Tips(備忘録)

  • 脆弱性は英語でvulnerability
  • 個人情報保護法は怖い
  • const cp = require('child_process');
    cp.execSync({任意のコマンド}); 
    で任意のコマンドを実行できる。
    外部からコマンド(の一部)を受け取るような設計にしているとOSコマンドインジェクションの危険性が高まる
  • execSync()のような関数はなるべく使わない

感想

最近、炎上してたサービスもあったし怖いねぇ。

基本的にはどうせ誰も使わねぇんだからどんどん公開してしまえ派なんだけど、ユーザーが入力してテキストがそのまま残っちゃうようなサービスの場合はやっぱり気をつけないとね。

カロリーメイトください。 

N予備校:プログラミング入門 Webアプリコースを学習する40

序文

N予備校のプログラミング入門 Webアプリコース40日目。
おなじみブートストラアアアアアップ!!!

f:id:yjkym:20180220154026p:plain

GitHub

github.com

客観的成果

  • N予備校 プログラミング入門 Webアプリ
    • 第3章 サーバーサイドプログラミング入門
      • 26.デザインの改善

(学習時間:3時間)

学習内容

  • faviconについて
  • Node.js : faviconを表示させる方法
  • Bootstrapについて
  • レスポンシブデザインについて
  • Bootstrapの導入方法
  • Bootstrap : containerクラスの使い方
  • Bootstrap : page-headerクラスの使い方
  • Bootstrap : button, btn-info, btn-dangerクラスの使い方
  • Bootstrap : pull-righクラスの使い方
  • Bootstrap : form-group, form-controleクラスの使い方
  • Bootstrap : panel, panel-default, panel-body, panel-footerクラスの使い方
  • Node.js : Moment Timezoneモジュールの使い方
  • Moment Timezone : moment-timezone.tz()関数の使い方
  • Moment Timezone : moment-timezone.tz.format()関数の使い方

個人的Tips(備忘録)

  • favicon.icoへのリクエストに対してレスポンスを返す実装例
    /**
    * faviconをレスポンスとして与える
    * @param {IncomingMessage} req
    * @param {ServerResponse} res
    */
    function handleFavicon(req, res) {
    // レスポンスヘッダにステータスコードとその他の情報を書き出す
    // 'image/vnd.microsoft.icon'はfaviconの'Content-Type'
    res.writeHead(200, {
    'Content-Type': 'image/vnd.microsoft.icon'
    })
    // faviconを読み取る
    const favicon = fs.readFileSync('./favicon.ico');
    // faviconを書き出して終了
    res.end(favicon);
    }
    Content-Typeには'image/vnd.microsoft.icon'を設定する。
    microsoftすごい。
  • jadeテンプレートでBootstrapを読み込んでいる部分の実装例
    //- <head>タグ内に書く
    //- CDNでBootstrapを読み込む
    //- href属性 : URL
    //- integrity属性 : CDN経由で参照したリソースの整合性を確認する仕組み。
    //- 値にSRI Hashの値を設定する。
    //- https://www.srihash.org/ でURLからSRI Hash値が取得できる
    //- crossorigin属性 : Anonymousの場合、クライアント側に認証情報を求めない。デフォルト値。
    link(rel="stylesheet",
    integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7",
    crossorigin="anonymous")
    //- Bootstrapオプションのbootstrap-theme.cssも読み込む。
    //- デフォルトのBootstrapよりグラデーションや立体感が出る
    link(rel="stylesheet",
    integrity="sha384-fLW2N01lMqjakBkx3l/M9EahuwpSfeNvV63J5ezn3uZzapT0u7EYsXMjQV+0En5r",
    crossorigin="anonymous")
     
    // 省略
     
    //- <body>タグの一番下に書く
    //- jQueryの読み込み
    //- Bootstrapで使用するjsファイルの読み込み
    integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS",
    crossorigin="anonymous")
    integrity属性とかcrossorigin属性とか習ってないよー。説明もまったくないよー。
    調べたらなんとなく理解できたけど。
  • Bootstrapのjadeテンプレート適用例
    title 秘密の匿名掲示板
    body(class="container")
     div(class="page-header")
      a(href="/logout", class="btn btn-info pull-right") ログアウト
      h1 秘密の匿名掲示板
     h2 新規投稿
     form(method="post", action="/posts")
      div(class="form-group")
       textarea(name="content", class="form-control", rows=4)
      div(class="form-group")
       button(type="submit", class="btn btn-info pull-right") 投稿
      //- 間隔の調整。邪道。
      div(class="row")
    h2 投稿一覧
    //- postsとして投げられた変数を1件ずつ処理
     each post in posts
      div(class="panel panel-default")
       div(class="panel-heading")
        //- postを投稿したユーザーが管理人かどうか
        - var isPostedByAdmin = (post.postedBy === 'admin')
        //- 管理人なら
        if isPostedByAdmin
         //- 変数埋め込み
         //- 管理人であることを表示する
         span #{post.id} : 管理人 ★
        else
          //- 管理人でないならクッキー値をIDとして表示する
         span #{post.id} : ID:#{post.trackingCookie}
        div(class="panel-body")
          //- HTMLタグを認識させる
         p!= post.content
        div(class="panel-footer")
         div 投稿日時: #{post.formattedCreatedAt}
         //- 閲覧中のユーザーが管理人かどうか
         - var isAdmin = (user === 'admin')
         //- 管理人なら
         if isAdmin
          //- 投稿者を表示する
          div 投稿者: #{post.postedBy}
         //- JavaScriptもかける
         - var isDeletable = (user === post.postedBy || isAdmin)
         if isDeletable
          form(method="post", action="/posts?delete=1")
           input(type="hidden", name="id", value="#{post.id}")
           button(type="submit", class="btn btn-danger pull-right") 削除
    インデント適当。

感想

今日はデザイン、というかBootstrapについて。

最初触ったときはうおおおお!すげえええええええ!!!って感じだったけど、さすがにフラットデザインも陳腐化してきた感じが否めない気がする。
だからあんまり勉強にも身が入らない!

最近はグリッドデザインとレイアウトのためだけに導入してることが多いかな。

それならもっと適当な方法もあるんだろうけどなかなか勉強の時間が…。

カロリーメイトください。 

N予備校:プログラミング入門 Webアプリコースを学習する39

序文

N予備校のプログラミング入門 Webアプリコース39日目。
ようやく入門コースも終りが見えてきたかな?

f:id:yjkym:20180219193126p:plain

GitHub

github.com

客観的成果

  • N予備校 プログラミング入門 Webアプリ
    • 第3章 サーバーサイドプログラミング入門
      • 25.管理者機能の実装

(学習時間:7時間

学習内容

  • 掲示板の管理機能の実装

個人的Tips(備忘録)

  • コールバック関数にふつう引数を与える必要はない

感想

特に新しい内容はなかったけど学習時間丸半日。

やっぱりコールバック関数がどう動いてるのかわからなくなって、知識の整理のために全部コメントを付けなおしていたからである。

object.doMethod(func)

みたいなソースコードがあって、funcが引数が必要なコールバック関数だった場合、funcにどうやって引数与えてるんだ???となってしまったんだけど、多分そういうのも全部objectが担ってるんだよね。

うん、何言ってるかわかんないよね。JavaScript難しいわ。

あ、そんなことで昨日のエントリの内容は誤った内容でした。

こんなブログ信用してる人いないからいいよね。

カロリーメイトください。 

N予備校:プログラミング入門 Webアプリコースを学習する38

序文

N予備校のプログラミング入門 Webアプリコース38日目。
毎日コツコツ勉強している僕に「努力しているのに収入があがらない人の○○の特徴」とかいう記事を見せないでください。
つらい(直球)。

f:id:yjkym:20180218155346p:plain

GitHub

github.com

客観的成果

  • N予備校 プログラミング入門 Webアプリ
    • 第3章 サーバーサイドプログラミング入門
      • 24.削除機能の実装

(学習時間:3.5時間)

学習内容

  • jade : jadeのテンプレート内に JavaScript のコードを記述する方法
  • jade : jade のテンプレートで条件分岐をする方法
  • sequelize : データベースからレコードを削除する方法
  • sequelize : Model.findById()関数の使い方
  • sequelize : bluebird<any>.destroy()関数の使い方
  • 認証と認可について

個人的Tips(備忘録)

  • jadeテンプレートにJavaScriptを埋め込む実装
    each post in posts
    h3 #{post.id} : ID:#{post.trackingCookie}
    p #{post.content}
    p 投稿日時: #{post.createdAt}
     //- - でJavaScriptを挿入できる。userはposts-handler.jsから渡している
     - var isDeletable = (user === post.postedBy)
     //- 削除権限がある場合
     if isDeletable
      //- 削除用フォームを表示する。ボタンを押すとactionで指定したURLへとぶ
      form(method="post", action="/posts?delete=1")
      input(type="hidden", name="id", value="#{post.id}")
      button(type="submit") 削除
      hr
  • 投稿を削除する部分の実装
    case 'POST':
    let body = [];
    req.on('data', (chunk) => {
    body.push(chunk);
    });
    /**
    * 実際に投稿を削除する処理
    */
    let deleteFunc = function () {
    // 配列を結合して、文字列に変換する
    body = Buffer.concat(body).toString();
    // URIエンコードされた形でデータが送信されてくるのでデコードしてやる
    const decoded = decodeURIComponent(body);
    // 'id={id}'の形式になっているのでsplitして取り出す
    const id = decoded.split('id=')[1];
    // 投稿を特定して取得する
    let post = Post.findById(id);
    /**
    * 実際に実際に投稿を削除する処理
    * @param {*} post sequelizeのModel
    */
    let del = function (post) {
    // もう一度閲覧中ユーザーと投稿したユーザーが同一かを確認する
    if (req.user === post.postedBy) {
    // 投稿削除
    post.destroy();
    // 削除処理が完了した旨を標準出力に書き出し
    console.info(
    `削除されました: user: ${req.user}, ` +
    `remoteAddress: ${req.connection.remoteAddress}, ` +
    `userAgent: ${req.headers['user-agent']} `
    );
    }
    // /postsにリダイレクト
    handleRedirectPosts(req, res);
    }
    /**
    * postが正常に取得できていればdel()関数を実行する
    * 第一引数:実行するCB関数
    *   CB関数の引数1:Bluebird<any> よくわからん。sequelize.Model
    */
    post.then(function (arg) { del(arg) });
    }
    req.on('end', deleteFunc);
    break;
    コールバック関数に無理やり引数を与えるのはよくないんだろうな…
    チェーンメソッドとかろくに説明してもらってないもん
  • DBのレコードをいじる前にクライアント側の認証と別にサーバーサイドでもしっかり認可すべし

感想

…postという文字列がいっぱい出てきてどれがどれのことかわからん…

const Post = require('./post.js');

…で、自作のモジュール読み込んでるんだが、post.js内で定義していないPost.findAll()関数が使えるのはなんでなのー。

let posts = Post.findAll({ order: 'id DESC' });

requireで呼び出すと継承みたいなことしてくれるのかなー。まさか違うもの指してるとかいうことないよねぇ。

アロー関数にまだ慣れてないので、コールバック関数に書き換えてごまかしながらやってるんだけど、コールバック関数に引数を渡す方法がよくわからん。

d.hatena.ne.jp

わざわざこういう記事になってるってことは変なやり方なんだろうなー。
でもなんか動いちゃうんだよなー。 

カロリーメイトください。 

N予備校:プログラミング入門 Webアプリコースを学習する37

序文

N予備校のプログラミング入門 Webアプリコース37日目。
魔が差して次の実践サーバーサイドプログラミングの章見てみたら、最終的に練習課題提出者数が50とかになってて戦慄しました。

f:id:yjkym:20180217140808p:plain

GitHub

github.com

客観的成果

(学習時間:3時間)

学習内容

  • ラッキングCookie,トラッキングIDについて
  • npm : cookiesモジュールの利用方法
  • JavaScript :ランダムな整数値を生成する方法
  • JavaScript : Math.random()関数の使い方
  • JavaScript : Maht.floor()関数の使い方
  • JavaScript : Number.MAX_SAFE_INTEGER定数の使い方
  • JavaScript : ちょうどN日後の日付、時刻を取得する方法
  • cookies : cookies.get()関数の使い方
  • スコープについて(今さら…?)
  •  cookies : cookies.set()関数の使い方

個人的Tips(備忘録)

  • ユーザーの行動を追跡するために付与されるCookie のことをトラッキングCookieCookieとして付与する値のことをトラッキングIDという
  • npmのcookiesモジュールの利用方法
    npm install cookies@0.5.1 --save
  • cookiesモジュールの利用方法
    // cookiesモジュール呼び出し
    const Cookies = require('cookies');
     
    // Cookie情報を管理するcookiesオブジェクトを生成する(まだ付与はしない)
    const cookies = new Cookies(req, res);
     
    /**
    * 生成されたcookiesにCookie情報を付与する
    * @param {CookiesFunction} cookies
    */
    function addTrackingCookie(cookies) {
    // cookiesにCookieが設定されていない場合
    if (!cookies.get(trackingIdKey)) {
    // ランダムな整数値を返す
    const trackingId = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
    // 現在時刻の24時間後のミリ秒形式の日付を取得する
    const tomorrow = new Date(new Date().getTime() + (1000 * 60 * 60 * 24));
    /**
    * Cookie情報をセットする
    * 第一引数:Cookie値のキーとして使用する文字列
    * 第二引数:Cookie
    * 第三引数:Cookie情報のオプションデータのオブジェクト
    *   expires:Cookieの有効期限
    */
    cookies.set(trackingIdKey, trackingId, { expires: tomorrow });
    }
    }

感想

Cookie登場。

まぁ、DBとかに比べれば分かりやすいかな?

ここに来て「 {} で囲まれた処理のことをスコープと呼びます。」とかいう説明が出てきて面食らった。

プログラミングを体系的に勉強するべく、N予備校に入ったはずなのに結局バッラバラに勉強している気がする。

カロリーメイトください。 

「はじめての確定拠出年金投資」大江英樹を読む2

序文

大江英樹氏の「はじめての確定拠出年金投資」2日目

はじめての確定拠出年金投資

はじめての確定拠出年金投資

 

読了成果

  • 「はじめての確定拠出年金投資」大江英樹
    • 第2章 始めるにはどうすればいいか(~P56)

(学習時間約1時間)

書籍内容(備忘録)

  • 掛け金の上限は他の年金制度とのバランスで決められている
  • 企業型DCが導入されている企業の中で、従業員拠出制度が導入されている企業のサラリーマンは個人型DCを利用できない
  • 専業主婦が加入するメリットは運用益が非課税になること(のみ)
  • 個人型DC加入方法①運営管理機関を選ぶ
    • サラリーマンが個人型DCを利用する場合には勤務先が事業者登録を行う必要がある
    • 個人型DCの申し込み手続きはインターネットで行う方法が主流
    • 運営管理機関を選ぶ基準①商品の種類と品ぞろえ
    • 運営管理機関を選ぶ基準②運営管理手数料(口座管理費用)
    • 運営管理機関を選ぶ基準③投資信託保有コスト(信託報酬)
    • 口座開設料はおおむね2,777円(高いところもある)
    • 口座管理費用は国民年金基金に支払う手数料、信託銀行にかかる手数料、金融機関が徴収する手数料からなる。
      前2つは定額。金融機関が徴収する手数料には差がある
    • 自営業からサラリーマンになったときなどに移管手数料がかかる運営管理機関もある
    • DCを利用して投資信託を利用する場合、購入時手数料はかからない。差が出るのは信託報酬の部分
    • 毎月2万円の掛け金を38年間積み立てた場合、信託報酬が0.65%とすると1,155,960円、一方0.2%とすると355,680円かかる
    • 「国内株式型」「国内債券型」「外国株式型」「外国債券型」のアセットクラスが揃っている金融機関を選ぶ
    • 野村證券は比較的信託報酬が安いらしい
    • SBI証券スルガ銀行は口座管理費用が無料
    • 国内を中心に選ぶのであればりそな銀行も安いらしい

感想

2章まで読了。分かりやすく書かれていたように思う。

後半にウェブサイトも紹介されていたが、さすがにステークホルダー感が否めなかったので紹介省略。

とりあえず楽天とSBIはすでに資料請求はしたはずだが、まだ届いていない。
もう何社かアフィを踏まずに直接資料請求してみよう。

カロリーメイトください。