機械系大学生の修行ログ

sh-lu0's Tech Blog

アイドルが力をくれる

Dockerでポートマッピングした時のエラー(ポートがすでに使われている)

docker-compose up -d --buildした時に起きたエラー

Error starting userland proxy: Bind for 0.0.0.0:80: unexpected error (Failure EADDRINUSE)

ホスト側ですでに同じポートが使われていないか調べる

$ sudo lsof -i -P | grep "LISTEN"
nginx       271         username    6u  IPv4 0x9c38e07fb14876af      0t0    TCP *:80 (LISTEN)

80番ポートはnginxが使用していたので,停止させる

nginx -s stop

参考にしたサイト

nginx起動、再起動 - Qiita

Dockerで80番へポートマッピングした際に起きたエラーについて | Hodalog

セキュリティ周りまとめ

XSSCSRF

XSS(Cross Site Scripting)

掲示版サイトのような、ユーザーの入力内容を表示するタイプのWebサイトの脆弱性を突く攻撃。

具体的には、攻撃者が「脆弱性を持つWebサイトに対してスクリプトを書き込む」リンクを表示するWebページを公開。 そのリンクにアクセスしてしまうと、脆弱性のあるWebページを介してスクリプトがユーザーのWebブラウザに送り込まれ、クライアントサイド・スクリプトとして実行されてしまう。 送り込まれるスクリプトは、セッションハイジャックのための、Cookie情報を公開するものや、 ウイルスをダウンロードするものなどが考えられる。

XSSへの対策

Webページに出力するデータのエスケープ処理 Webページの出力に際して特別な意味を持つ文字列(例えば「<」、「&」など)は、単なる文字列として出力する。 また、エスケープの対象としては、利用者が画面から入力した値はもちろん、 外部システムからのデータなど、Webページの出力対象となるものは必ずエスケープすることが重要である。

CSRF (Cross Site Request Forgeries)

XSSと同じく、攻撃者が用意した「ログインが必要なサイトに対して操作を行う」リンクに ユーザーがアクセスすることで被害を受ける攻撃。

XSSと異なる点は、目的が「ユーザーのwebブラウザに悪意のあるスクリプトを送り込む」ことではなく、 「本人になりすましてログインの必要なサイトを操作する」ことである。 具体的な攻撃としては、ユーザーのパスワードを攻撃者の指定するものに変えてしまったり、 XSSのための悪意あるリンクを投稿することなどが考えられる。

CSRFへの対策

Formページ返却時のトークン付与 掲示板を例にすると、はじめに掲示板への書き込み画面を表示する際に、サーバがクライアントに対して特定の文字列(トークン)を設定する。 実際に書き込みのリクエストがあった際に、サーバーが「この人に送ったトークンと同じトークンがリクエストに入っているか」を確認することで、 攻撃者からの不正なリクエストを防ぐことができる。これは、攻撃者は利用者に送信したトークンの値を知らないためである。

補足

エスケープ処理(サニタイジング

エスケープ処理とは、マークアップ言語やプログラミング言語スクリプト言語等で文字列を扱う際に、 その言語にとって特別な意味を持つ文字や記号を、別の文字列に置き換えること。

例えばHTMLでは、タグの記述に「<」「>」という記号(文字)を使用する。 これらの記号をHTMLの中で使うと、Webブラウザはこれらを「タグ記述の記号」とみなすため、文字として表示することができない。 そこで「<」を表示する場合には「<」、「>」を表示する場合には「>」という文字列を、HTMLの中に記述する。 Webブラウザはこれらのエスケープ文字列を、表示の際に「<」「>」に置き換えて表示します。この処理をエスケープ処理と呼ぶ。

トーク

Webサービスを利用するために、認証局がユーザーを認証するために払い出した認証情報。 ここで言う認証局とは、ユーザーを認証する情報を保持しておりユーザーを認証することができるWebサーバーを示す。

通常、ユーザー認証が必要なWebサービスを利用する場合、メールアドレスなどのログインIDとパスワードを入力し、Webサービスを利用する。 この際、一度入力したメールアドレスなどのログインIDやパスワードを、各認証ページに引き継ぐことはセキュリティの観点からは危険なため、 認証局は初回ログイン以降にユーザーを認証するための、アクセストークンを払い出し、 初回ログイン以降は、払い出したアクセストークンでユーザーを認証を行う。 アクセストークンは認証局により様々だが、ユニークなランダムな英数字をそれなりの長さ(16桁、32桁、64桁など)で払い出すのが一般的。 例:zf14dffq3fg46ghg7dip1ash74ioisud また、払いだされたアクセストークンは、初回ログイン以降にWebサーバーで認証する必要があるため、Cookie(クッキー)やセションなどに保持しておく必要がある。

脆弱性

脆弱性(ぜいじゃくせい)とは、コンピュータのOSやソフトウェアにおいて、 プログラムの不具合や設計上のミスが原因となって発生した情報セキュリティ上の欠陥のことを言う。 脆弱性は、セキュリティホールとも呼ばれる。

SQL Injection

wikipedia:

アプリケーションのセキュリティ上の不備を意図的に利用し、 アプリケーションが想定しないSQL文を実行させることにより、データベースシステムを不正に操作する攻撃方法のこと。 また、その攻撃を可能とする脆弱性のことである。 SQLインジェクション攻撃への対策|脆弱性を悪用する仕組みと具体例

サーバでの対策

サニタイジングエスケープ)処理 SQLインジェクションは、主にWebアプリケーションのプログラムに問題がある。 その問題は、入力した文字列にSQL文を仕込まれた場合に、それを命令文と認識してしまうことである。 そのため、SQL文を成り立たせない実装で対策を行う。

サニタイジングエスケープ処理は同じか?

ほぼ同じ。

サニタイジング(無害化)の方法の一つが文字の変換などによるエスケープ処理。 サニタイジングの方法は、エスケープ処理以外に、特殊文字は入力させない(バリデーション)、処理を強制終了させるなどがある。 又は、もっと単純に、’などの特殊文字をそもそも受け付けず、入力フォームにてエラーを出すことも方法の一つ。

http://sc.seeeko.com/archives/3841214.html

ネットワークでの対策

WAF(Webアプリケーション・ファイアウォール)を使う。

WAFは、Webアプリケーションに送られる通信をチェックするのですが、 WAFはさまざまな脆弱性に対する攻撃コードをシグネチャとして持っていて、これと合致するコードを無効化する。 つまり、脆弱性を解消するのではなく、その脆弱性を悪用しようとする攻撃を検知して対策を行う。 導入や管理・運用が容易なクラウド型のWAFも複数提供されているため、脆弱性対策として導入を検討することも方法のひとつ。

URLエンコード

URLエンコードには2種類ある。 RFC3986にて規定されているUniform Resource Identifer(URI)の仕様の一部として定められているもの HTMLのFormで送信するデータ種類の1種である、application/x-www-form-urlencoded の仕様として定められているもの

文字コード

文字コードとは、コンピュータなどの電子媒体において、 文章を画像などの図形データとして扱わずに、テキストの形式で扱う場合に、 その各文字(単一の文字でない場合もある)に対して持っているコードのことである。

HTTP Header Injection

HTTPヘッダインジェクションは、HTTPレスポンスヘッダの出力処理に関するサイバー攻撃。 攻撃者が罠サイトにURLを配置し、利用者がクリックすることで特定の値がCookieにセットされる。 その結果、成りすまし攻撃が成立してしまう可能性がある。 また、同様の攻撃手法でURLに「%0D%0ALocation〜」のような文字列を含めることで、 リダイレクト先のURLを任意のURL(罠サイト等)に書き換えることも可能。

HTTP Header Injectionの原因

HTTPレスポンスは「改行と空白行によって分割されている」 そのため、URLに「%0D%0A」(改行コード)を含める事により、「%0D%0A」以降の文字列が次の要素として扱われてしまい、 Set-Cookieヘッダが有効になってしまう。 なお、レスポンスヘッダとレスポンスボディは空白行で分割されているため、 「%0D%0A%0D%0A」のように連続で改行コードを入れることで、レスポンスボディに任意のHTMLやJavaScriptを挿入するような攻撃も可能。

HTTP Header Injectionの対策

外部からのパラメータをHTTPレスポンスヘッダに出力しないようにする。 例えば、「redirect_url」に指定された値をそのまま出力するのではなく、

「redirect_url」に”456″が入力されていた場合は、「http://example.com/456」にリダイレクトするという実装になっていれば問題は発生しない。 「Location」に出力されるのは、必ず「http://example.com/456」等の固定値であり、外部からのパラメータがそのまま入ることはない。

OS Command Injection

OSコマンドインジェクションは、シェルによるOSコマンドの実行において、意図しないOSコマンドが実行されてしまう攻撃。 この脆弱性が存在する場合、想定外のコマンドにより秘密情報の漏洩やデータの改ざんなど様々な問題が発生する可能性がある。

OS Command Injectionの原因

シェルコマンドには、一行で複数のコマンドを実行する方法を提供しており、「;」の後の文字列は別のコマンドとして扱われる。 そのため、攻撃者が「test@example.co.jp; rm -rf /home/test_user」を入力した場合、下記コマンドが実行されてしまい、 「/home/test_user」配下の全てのファイルおよびディレクトリが削除される。

OS Command Injectionの対策

根本的な対策として、OSコマンドを直接実行する関数を利用しないことが重要。 メール送信が目的であれば、メール送信用のライブラリを利用すれば、コマンドを実行せずにメール送信機能が利用できる。 なお、OSコマンド呼び出し関数を利用する場合でも、ユーザーの入力値など、 外部から入力されたデータを関数のパラメータに渡さず、固定値をパラメータにしているような場合は問題はない。 もし、どうしても外部から入力されたデータを、OSコマンド呼び出し関数のパラメータに渡す必要がある場合は、 エスケープ処理のライブラリ※を利用して事前にパラメータをエスケープした上で、OSコマンド呼び出し関数に渡すようにするべきである。 ※PHPのescapeshellargやRubyのShellwordsなど。

ホワイトリスト

ホワイトリストとは、対象を選別して受け入れたり拒絶したりする仕組みの一つで、 受け入れる対象を列挙した目録を作り、そこに載っていないものは拒絶する方式。また、そのような目録のこと。 対義語は「ブラックリスト」(black list)で、目録に載っているものだけを拒絶し、それ以外は受け入れる方式である。 ホワイトリスト(WL)とは - IT用語辞典 e-Words

ディレクトリトラバーサル攻撃

ディレクトリトラバーサル(directory traversal)とは、本来アクセスして欲しくないファイルやディレクトリの位置を、 相対パス指定などでプログラムに表示させて、不正なアクセスをする攻撃手法。 ほぼ全てのサーバーはディレクトリによる構造があり、プログラムやコード内でもURLを参照したり、 位置を指定することで可動する仕組みとなっており、正しく動作することを悪用した防ぎにくい攻撃であると言える。

ディレクトリトラバーサルの対策

外部からの入力による相対パス指定を対策 まず、相対パスまたはパラメータが外部から入力された時に、サーバーやプログラムがどのように処理するかを把握する必要がある。 把握した上で、外部からの入力によって渡されたパラメータによって、ファイル名を直接指定しない方法や、 相対パスが正規化される際に前方一致を行う方法、または一部の一致を確認する方法がある。 ディレクトリトラバーサルを検知する対策 外部からのパラメータ入力による処理を把握し、実行するパスの指定などで対策をする方法とは別で、 ディレクトリトラバーサルによる攻撃を受けた際に検知する仕組みを導入するのも有効である。 また、検知に加えて、プログラムが求めるパス形式ではない形式で不正なアクセスがあった場合、 新たなディレクトリトラバーサル攻撃のパターンを蓄積することで、日々変化してしまうサーバー攻撃に対する情報を増やす。

NULLバイト攻撃

  • ヌルバイト攻撃とは、何らかのリクエストされた文字列に%00(ヌルバイト)を含めることで、 Webアプリケーション側のセキュリティーチェックをくぐり抜ける攻撃。

  • 例えば%00は文字列の終りを意味するコードである。 eregはコレを入力文字列の終了部分と判断するため、それより後の文字列はノータッチ(無審査)である。 そのため、ヌル文字より後に攻撃用の文字列が書かれていてもeregではそれを検出できない。

  • この攻撃はディレクトリ遡りと併用される。

  • PHPは、ファイルシステムに関わる処理においてC言語の関数を用いているため、Nullバイト処理で挙動がおかしくなることがある。 ※PHP 5.4.0以降では引数としてファイル名を受け取る関数にヌル文字を含んだ文字列を渡すと警告がでる

NULLバイト攻撃への対策(ヌルバイトアタック)

  • ヌルバイトを一切許可しない デメリット:バイナリデータを直接受け渡しできなくなる

  • ホワイトリストではじく preg_matchで使用可能な文字列のみ許可する。

バイナリデータ

wikipedia

バイナリ (binary) とは二進法のことであるが、 コンピュータが処理・記憶するために2進化されたファイルまたはその内部表現の形式(バイナリデータ)のことを指して用いることが多い。

Vue.jsインストールからGitHubPagesで公開するまで

環境

$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.14.1
BuildVersion:   18B75

$ node -v
v10.14.1

$ npm -v
6.7.0

環境構築

npmインストール

homebrewインストール

$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

Node.jsインストール

$ brew install node

確認

$ npm -v

Vue.jsインストール

$ # vue-cli をインストール
$ npm install --global vue-cli
$ vue --version
2.9.6

vue-cliは雛形からプロジェクトを作成してくれる公式ツールです.

プロジェクト作成

vue init <template> <project-name>でプロジェクトを作成. "webpack" ボイラープレートを使用している.

$ vue init webpack my-project
$ cd my-project
$ npm run dev

起動

DONE  Compiled successfully in 119ms                                                                                         23:51:58

 I  Your application is running here: http://localhost:8080

http://localhost:8080にアクセス

GitHub Pagesに公開

docsディレクトリを生成

GitHub-pagesでは,./docsディレクトリが配信されるため,/config/index.jsを修正する.

/config/index.js

var path = require('path')

module.exports = {
  build: {
    env: require('./prod.env'),
    index: path.resolve(__dirname, '../docs/index.html'), // (1)
    assetsRoot: path.resolve(__dirname, '../docs'), // (2)
    assetsSubDirectory: 'static',
    assetsPublicPath: './', // (3)
    productionSourceMap: true,
    productionGzip: false,
    productionGzipExtensions: ['js', 'css'],
    bundleAnalyzerReport: process.env.npm_config_report
  },
  dev: {
    env: require('./dev.env'),
    port: 8080,
    autoOpenBrowser: true,
    assetsSubDirectory: 'static',
    assetsPublicPath: '/',
    proxyTable: {},
    cssSourceMap: false
  }
}

ビルドする

npm run build

docsディレクトリが生成される. f:id:sh_lu0:20190307002631p:plain
masterにpushする.

公開設定

リポジトリのSettingsをクリック GitHub Pages->Sourceで 「master branch / docs folder」を選択. 数分後公開される.

参考にしたサイト

vue-cliで始めるVue.jsチュートリアル (2) - Qiita

対象のオブジェクトがクリックされたか調べる(2D)

RayCastとは

Rayとは「画面から無限の奥までまっすぐに貫く光線」
クリックした位置から無限大の奥までRayを発射して,このレーザービームがゲームオブジェクトを貫いているかどうかを調べることで,クリックされたかどうか判断できる.これを「Rayを飛ばす」というらしい.

対象のオブジェクトをタッチしたときだけ処理するスクリプト(2D)

  • 対象のオブジェクトにスクリプトをアタッチ
  • 対象のオブジェクトに2Dコライダーを追加
  • タッチ判定の範囲を広げたかったらコライダーを変更する

対象のオブジェクトがタッチされると小さくなるスクリプト

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RayTest : MonoBehaviour {

    GameObject clickedGameObject;
    Vector2 smlSize;

    void Start(){
        smlSize = new Vector2(0.5f, 0.5f);
    }

    void Update()
    {

        if (Input.GetMouseButtonDown(0))
        {

            clickedGameObject = null;

            //指定の位置から発射されるRayを作成
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            //Rayとオブジェクトの接触を調べる
            RaycastHit2D hit2d = Physics2D.Raycast((Vector2)ray.origin, (Vector2)ray.direction);

            //接触してたらオブジェクトを小さくする
            if (hit2d)
            {
                clickedGameObject = hit2d.transform.gameObject;
                hit2d.transform.localScale = smlSize;
            }

            Debug.Log(clickedGameObject);
        }
    }

}

上のコードだと,スクリプトをアタッチしたオブジェクトの他にも2Dコライダーを持っているオブジェクトを感知してしまった.
接触してるかどうかを判別するコードを以下に変更

if (hit2d && clickedGameObject.name=="オブジェクト名")

詰まった点

  • Physics.Raycastは3Dでしか使えない→Physics2D.Raycast
  • 2DではRayが引数にできない
  • 3DではRaycastHitを参照渡しだったが,2Dだと返り値自体がRaycastHit2D

初心者本はInput.GetMouseButtonDownだけの例が多くて,どのオブジェクトがタッチされたかの判別はどうするんだ〜〜から「Rayを飛ばす」という言葉に出会って,2Dの書き方に変更するまでちょっと時間かかった.

参考にしたサイト

Physics2D.Raycast - Unity スクリプトリファレンス
RayCastその4、Raycastを2Dで使う【Unity】 - (:3[kanのメモ帳]
【Unity】クリックしたゲームオブジェクトを取得する
ありがとうございます.

Babel用の設定ファイルを作成

手順

  1. npm initでプロジェクト初期化
  2. ライブラリをインストール
  3. Babel設定ファイル「.babelrc」を作成
  4. JSファイルを変換

プロジェクト初期化

$mkdir babeltest
$ cd babeltest/
$ npm init

ライブラリをインストール

「Babel CLI」と「ES2015」をプロジェクトにインストール

$ npm install --save-dev babel-cli
$ npm install --save-dev babel-preset-es2015

Babel設定ファイル「.babelrc」を作成

  • プロジェクトフォルダに「.babelrc」ファイルを作成
  • 以下の内容を追加
{"presets": ["es2015"]}

JSファイルを変換

$ babel ファイル名.js -o ファイル名.out.js 

package.jsonにコマンドを登録

先ほどの変換処理をbuild時に行うように以下を追加

  "scripts": {
    "start": "node hello.js",
    "build": "babel hello.js -o hello.out.js"
  },

ビルドして実行

$ npm run build

> babeltest@1.0.0 build /Users/username/Projects/babeltest
> babel hello.js -o hello.out.js
$ npm run start

> babeltest@1.0.0 start /Users/usernamei/Projects/babeltest
> node hello.js

監視モードを追加 プログラムを書き換えるたびに変換してくれる

  "scripts": {
    "start": "node hello.js",
    "build": "babel hello.js -o hello.out.js",
    "watch": "babel hello.js -w -o hello.out.js"
  },

プログラムの開発を始めるときに使う

$ npm run watch

Node.jsの環境構築・HelloWorld (Mac)

Homebrewインストール

macOS 用パッケージマネージャー — macOS 用パッケージマネージャー
インストールする

$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

パスワードを求められるのでmacのパスワードを入力 ※Xcodeがインストールされている必要がある

バージョン確認

$ brew --version
Homebrew 1.8.4
Homebrew/homebrew-core (git revision 9d67f4; last commit 2018-12-06)

Nodebrewインストール

インストール

$ brew install nodebrew

バージョン確認

$ npm view node version
11.3.0

Node.jsインストール

最新バージョンをインストール

$ nodebrew install-binary latest

エラーがでた

Fetching: https://nodejs.org/dist/v11.3.0/node-v11.3.0-darwin-x64.tar.gz
Warning: Failed to create the file
Warning: /Users/hoge/.nodebrew/src/v11.3.0/node-v11.3.0-darwin-x64.tar.gz:
Warning: No such file or directory
                                                                           0.0%
curl: (23) Failed writing body (0 != 847)
download failed: https://nodejs.org/dist/v11.3.0/node-v11.3.0-darwin-x64.tar.gz

ディレクトリ作成

$ mkdir -p ~/.nodebrew/src

出来た

$ nodebrew install-binary latest  
Fetching: https://nodejs.org/dist/v11.3.0/node-v11.3.0-darwin-x64.tar.gz
######################################################################## 100.0%
Installed successfully

バージョン確認

$ node --version
v10.14.1

npmでプロジェクト作成

$ mkdir project_name
$ cd project_name
$ npm init //npmでプロジェクトを開始する

package.jsonが作成される

{
  "name": "project_name",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "sh-lu0",
  "license": "ISC",
    "description": "",
}

$ npm install ライブラリ名 --saveでライブラリをインストールすると,自動でpackage.jsonにインストールしたモジュールとバージョンが記録される.

Node.jsでWebサーバーを立てる

先ほど作ったプロジェクトの中にhello-server.jsを作成

// httpモジュール読み込み
const http = require('http')

// webサーバーを実行
const svr = http.createServer(handler) //Webサーバー生成
svr.listen(8081) //クライアント(ポート8081)で待ち受け開始

//サーバーにアクセスされたとき
function handler(req, res) {
  console.log('url:', req.url)
  console.log('method;', req.method)
  //HTTPヘッダーを出力
  res.writeHead(200, {
    'Content-Type': 'text/html'
  })
  //レスポンスの本体を出力
  res.end('<h1>Hello,World</h1>\n')
}

ターミナルで

$ node hello-server.js

Webブラウザhttp://localhost:8081にアクセス
f:id:sh_lu0:20181209012042p:plain
やったね!



参考にしたサイト
MacにNode.jsをインストール - Qiita
ありがとうございます

MySQLのストレージを意識する

めちゃ長い数をINSERTしたら限界って怒られた

14桁のidつっこんだところ

ERROR 1264 (22003): Out of range value for column 'id' at row 1
mysql> DESC items;
+-----------+------------------+------+-----+---------+----------------+
| Field     | Type             | Null | Key | Default | Extra          |
+-----------+------------------+------+-----+---------+----------------+
| id        | int(11) unsigned | NO   | PRI | NULL    | auto_increment |
| parent_id | int(11)          | YES  |     | NULL    |                |
| message   | varchar(100)     | YES  |     | NULL    |                |
+-----------+------------------+------+-----+---------+----------------+

int(11)だからかな・・・??

文字数制限増やしたらええやろ! idの長さをint(11)→int(20)に変更

私「20桁までいけるで!」

ERROR 1264 (22003): Out of range value for column 'id' at row 1

o(;△;)o

ストレージを考慮すべきだった

文字数の長さとは別に,ストレージでINSERTできる容量が決まっていた.

MySQL :: MySQL 5.6 リファレンスマニュアル :: 11.7 データ型のストレージ要件 MySQLデータ型一覧 (詳細) - Miuran Business Systems

型名 必要なストレージ  符号なしの範囲 
TINYINT 1バイト  0~255 
INT 4バイト  0~4294967295 (43億) 

文字数制限を20文字に増やしても,ストレージがオーバーしていればINSERTできない.

ビットとバイト

bit(binary digit) 二進法の 数字 → 二進数
コンピュータ内部における情報表現の最小単位で、データの容量を表す単位 0か1の2通り

1ビット→2通り
2ビット→22→4通り
8ビット→28→256通り

byte
1バイト=8ビット
1バイト→8ビット→28→256
4バイト→232→4294967296

まとめ

  • 型ごとに必要なストレージが決まってる
  • 符号ありの場合は,1番前のビットが±に使われて4バイトの場合27となって,データ量が半分になる
  • TINYINTは1ビットで足りるが,デフォが1バイト=8ビットなので,文字数制限1にしてエラーを防ぐ
  • INTで足りないような莫大なデータを使用する時はBIGINT(8バイト)にする