君は心理学者なのか?

大学時代に心理学を専攻しなぜかプログラマになった、サイコ(心理学)プログラマかろてんの雑記。

macのlocal環境にtypescriptを導入

f:id:karoten512:20180303225527p:plain

職場が静的型付け言語使ってきた人が多いので、

その人達の学習コストの事だったり

コンパイル時にバグを発見できたりであったり

そんな事情でtypescriptを使っています。

導入の仕方の備忘録。

typescriptの導入

1. typescriptをglobal install

npm install -g typescript

2 . コードを書く

class Dog {
  private name: string;

  constructor(name: string) {
    this.name = name;
  }
}

const dog = new Dog('pochi');

3. typescriptからJavaScriptコンパイルする

tsc hello.ts

こんなjsファイルが生成されます。

var Dog = /** @class */ (function () {
    function Dog(name) {
        this.name = name;
    } 
    return Dog;
}());
var dog = new Dog('pochi');

webpackの導入

いちいちコンパイルするの面倒くさいよね。

ファイル保存時に自動でコンパイルしてくれたらうれしい

コンパイルが終わった後にいちいちブラウザリロードするの、
面倒くさいよね。

コンパイルが終わったら自動でブラウザをリロードしてくれるとうれしい

コード量が増えたらファイル分けたいよね。

外部ファイルが読み込めるようになったらうれしい

webpackを導入しましょう。

(次回の記事)

地下アイドル「私、ぜったい売れっ子アイドルになるんだから!」で学ぶデザインパターン(Observer)〜アイドルとオタクを疎結合にしてみた〜

f:id:karoten512:20180226001228p:plain

ある日の地下アイドル

地ア「は〜あ。今日もライブは3人しかこなかったなぁ」

地ア「きょう来てくれたのは、たっくんと、しのぶんと、ゆっきーか」

地ア「この3人、いつも来てくれるんだよねぇ。大事にしなくちゃ」

地ア「私、ぜったいに売れっ子アイドルになるんだから!」

地ア「…そろそろCD発売だから、告知しよっと」

アイドルクラス

/** アイドルクラス */
function ChikaIdle() {
}

ChikaIdle.prototype.noticeCdRelease = function() {

  /** わたし、みんなの名前も顔も覚えてるよ! */
  var takkun   = new Otaku('takkun');
  var shinobun  = new Otaku('shinobun');
  var yukki = new Otaku('yukki');
  
  /** CD買って(はあと) */
  console.log('みんなだいすき!CD買ってね!');
  takkun.getCd();
  shinobun.getCd();
  yukki.getCd();
}

アイドルによる告知

var chikaIdle = new ChikaIdle();
chikaIdle.noticeCdRelease();

オタククラス

/** オタククラス */
function Otaku(name) {
    this.name = name;
}
Otaku.prototype.getCd = function() {
    console.log(this.name + 'はCDをぜってーかうぜ!!');
}

告知結果

みんなだいすき!CD買ってね!
takkunはCDをぜってーかうぜ!!
shinobunはCDをぜってーかうぜ!!
yukkiはCDをぜってーかうぜ!!

だんだん売れてきた地下アイドル

地ア「今日は10人もライブに来てくれた!!」

地ア「きょう来てくれたのは、たっくんと、しのぶんと、ゆっきーと、ちーくんと、るなくんと、、、」

地ア「ほげくんとほげくんとほげくんかぁ」

地ア「そろそろCD発売だから、また告知しよっと」

アイドルクラス

/** アイドルクラス */
function ChikaIdle() {
}
ChikaIdle.prototype.noticeCdRelease = function() {

  /** わたし、みんなの名前も顔も覚えてるよ! */
  var takkun   = new Otaku('takkun');
  var shinobun  = new Otaku('shinobun');
  var yukki = new Otaku('yukki');
  var chi = new Otaku('chi');
  var luna = new Otaku('luna');
  var hoge1 = new Otaku('hoge1');
  var hoge2 = new Otaku('hoge2');
  var hoge3 = new Otaku('hoge3');
  var hoge4 = new Otaku('hoge4');
  var hoge5 = new Otaku('hoge5');

  console.log('みんなだいすき!CD買ってね!');
  /** CD買って(はあと) */
  takkun.getCd();
  shinobun.getCd();
  yukki.getCd();
  chi.getCd();
  luna.getCd();
  hoge1.getCd();
  hoge2.getCd();
  hoge3.getCd();
  hoge4.getCd();
  hoge5.getCd();
}

アイドルによる告知

var chikaIdle = new ChikaIdle();
chikaIdle.noticeCdRelease();

メッチャ売れてきたアイドル

地ア「すごい!今日ははじめて箱(ライブハウスのこと)がいっぱいになったよ!」

地ア「200人も来てくれた!」

地ア「今日来てくれたのはたっくんと、しのぶんと、ゆっきーと、ちーくんと、るなくんと、、、」

f:id:karoten512:20180226003450j:plain

地ア「アアアアアアアアアアアアアアアアアアアアアア!!!!!!!」

しのぶん「地下アイドルちゃん!僕の事今日から、しのぶーって読んでね!」

/** アイドルクラス */
function ChikaIdle() {
}
ChikaIdle.prototype.noticeCdRelease = function() {
  /** わたし、みんなの名前も顔も覚えてるよ! */
  // var shinobun  = new Otaku('shinobun');
  var shinobu  = new Otaku('shinobu');
  // shinobun.getCd();
  shinobu.getCd();
}

f:id:karoten512:20180226003618j:plain

地ア「ア゛ア゛ア゛ア゛ア゛ア゛ア゛ア゛ア゛ア゛ア゛ア゛ア゛!!!!!!!」

どうしてこうなったのか

地下アイドルがいろいろ知りすぎです。

f:id:karoten512:20180226004952p:plain

このままでは、

オタク達が増えるたびに地下アイドルクラスに変更が行われ、

オタク達のあだ名が変わるたびにまた、地下アイドルクラスに変更が行われます。

つまり、

地下アイドルクラスはめちゃくちゃ仕様変更に弱いクラスということになります。

その時、地下アイドルは気づいた

地ア「そうだ!」

地ア「私は別に、みんなの名前を覚えなくていいんだ!」

これがObserverパターンの始まりです(嘘)

Observerパターンで書き直す

アイドルクラス

/** アイドルクラス */
function ChikaIdle() {
    this.fans = [];
}

ChikaIdle.prototype.addFan = function(fan) {
    this.fans.push(fan);
}

ChikaIdle.prototype.noticeCdRelease = function() {
  console.log('みんなだいすき!CD買ってね!'); 
  /*
   * アイドルはファンの名前は誰も知らない。
   * 知っているのはCDを買ってくれるということだけ
   */
  this.fans.forEach(function(fan, index, fans) {
    fan.getCd();
  });
}

アイドルクラスから、

Otakuクラス、

Otakuの名前が全て消えました。

f:id:karoten512:20180226010800p:plain

アイドルが知っているのは、

fanが「getCd」というメソッドを持っていることだけです。

もう、アイドルはオタクの顔も名前も思い出せません。

知っているのは、「告知をしたら、CDを買ってくれる」というただ1つだけ。。。

アイドルとオタクが非常に疎結合な、良い設計になりました。

使い方

var chikaIdle = new ChikaIdle();

var takkun   = new Otaku('takkun');
var shinobun = new Otaku('shinobun');
var yukki    = new Otaku('yukki');
var chi      = new Otaku('chi');
var luna     = new Otaku('luna');
var hoge1    = new Otaku('hoge1');
var hoge2    = new Otaku('hoge2');
var hoge3    = new Otaku('hoge3');
var hoge4    = new Otaku('hoge4');
var hoge5    = new Otaku('hoge5');

chikaIdle.addFan(takkun);
chikaIdle.addFan(shinobun);
chikaIdle.addFan(yukki);
chikaIdle.addFan(chi);
chikaIdle.addFan(luna);
chikaIdle.addFan(hoge1);
chikaIdle.addFan(hoge2);
chikaIdle.addFan(hoge3);
chikaIdle.addFan(hoge4);
chikaIdle.addFan(hoge5);

chikaIdle.noticeCdRelease();

さらなるメリット

アイドルは、CDを買ってくれる人ならだれでも通知することが出来ます。

/** 一般ピーポークラス */
function IppanPeople(name) {
    this.name = name;
}
IppanPeople.prototype.getCd = function() {
    console.log(this.name + 'はちょっと興味があるからCDかうよ');
}

getCdメソッドを持つクラスをまとめて扱うことが出来ます。

疎結合にしたことにより、ポリモーフィズムも使えるようになりました。

まとめ1

Observerパターンは、通知する側とされる側を疎結合にする。

疎結合にした結果、ポリモーフィズムも使えるようになる。

まとめ2

アイドルとオタクを疎結合にすると、

アイドルはオタクの顔も名前も覚えなくなり、

知っているのは「告知をしたら、CDを買ってくれる」というただ1つだけという

夢も希望もなくなる感じになる。

【JavaScript】画像をdrag and dropしてサムネイルを表示する〜DragEvent, DataTransfer, File, FileReaderオブジェクトについて〜

こういうのがやりたかった

f:id:karoten512:20180223161259g:plain

手順

簡単に言うと、

  • DragEventからDataTransferを取得

  • DataTransferからFileを取得

  • FileをFileReaderで読み込み、サムネイルとして表示

という手順になります。

1. dropエリアの準備

1-1. まずはdropエリアを作成する

imgは後でサムネイルを表示する際に使います。

<div id='droparea'>
</div>
<img src='' id='thumb'>
#droparea {
  width: 200px;
  height: 100px;
  border: 3px dotted #ccc;
}

1-2. dropエリアにイベントリスナを登録

const droparea = document.getElementById('droparea');
droparea.addEventListener('drop', function(evt) {
  console.log('dropしたよ');
  /** 以下、drop後の処理 */
}, true);

この中にdrop後の処理を書き込んでいきます。

2. dragしたファイル(Fileオブジェクト)を受け取る

dropしたファイルを取得します。

まず、dropイベントの中身を見てみましょう。

console.log(evt);

f:id:karoten512:20180223153824p:plain

DragEventというオブジェクトのようです。

今回用があるのは、このオブジェクトが持つ

DataTransferというオブジェクトです。

console.log(evt.dataTransfer);

f:id:karoten512:20180223154003p:plain

DataTransferオブジェクトがもつfilesというプロパティから、

ドラッグされたFileオブジェクトにアクセスすることが出来ます。

/** 全件取得 */
console.log(evt.dataTransfer.files);
/** 1件取得 */
console.log(evt.dataTransfer.files[0]);

f:id:karoten512:20180223153619p:plain

複数件まとめて扱うこともできそうですね。

3. 取得したFileオブジェクトを、FileReaderで読み込む

ソースコード

droparea.addEventListener('drop', function(evt) {
  // ファイルオブジェクトの取得
  const file = evt.dataTransfer.files[0];
  
  // FileReaderの生成
  const reader = new FileReader();
  
  reader.onload = function() {
    // ファイルを読み込んだ後の処理
    console.log(reader.result);

    // サムネイルとして表示
    const thumb = document.getElementById('thumb');
    thumb.src = reader.result;
  };

  // ファイルの読み込み
  reader.readAsDataURL(file);
 
  // ブラウザのデフォルト挙動を抑制
  evt.preventDefault();

}, true);

FileReaderの解説

html5から、

FileReaderというローカルファイルを読み込めるAPIが使えるようになりました。

FileReaderが扱えるのはFileオブジェクト(またはBlobオブジェクト)です。

reader.onload = function() {
  // ファイルを読み込んだ後の処理
  // reader.resultでファイル内容にアクセスできる
};

としてファイルを読み込んだ後の処理を記載します。

読み込んだ結果は、

reader.resultでアクセスできます。

reader.readAsDataURL(file);

としてファイルオブジェクトを読み込みます。

完成したソースコード

const droparea = document.getElementById('droparea');

// dropイベントのリスナーを設定
droparea.addEventListener('drop', function(evt) {

  // Fileオブジェクトの取得
  const file = evt.dataTransfer.files[0];
  
  // FileReader生成
  const reader = new FileReader();
  
  // ファイルを読み込んだ後の処理
  reader.onload = function() {
      // サムネイルとして表示
      const thumb = document.getElementById('thumb');
      thumb.src = reader.result;
  };

  // ファイルの読み込み
  reader.readAsDataURL(file);

  evt.preventDefault();

}, true);

bashで特定の文字列を含むファイルの名前を、一括置換する

f:id:karoten512:20180220003702j:plain

bashである文字列を含むファイルについて、一括置換したかった

カレントディレクトリにあるファイルのうち、

無題を含むものをmudaiに変える、みたいなことがしたかった。

結論

解説

まず、以下のようにファイルを準備します。

$ touch hogeA hogeB fugaC

これらのファイルのうち、以下の2つのファイル名を

hogeA -> ho:)geA
hogeB -> ho:)geB

と変更することにします。

for文

こう書けば、カレントディレクトリのファイルについて

ループ処理をすることが出来ます。

# run.sh
for file in *
do
  echo ${file}
done
$ sh run.sh
fugaC
hogeA
hogeB

sed

新しいファイル名を生成する際、正規表現を使うことがあります。

そのときはこのsedを使いましょう。

以下のように使うことが出来ます。

$ echo hogeA | sed -E 's/(ho)(ge)/\1:)\2/g'
ho:)geA

-E オプション

正規表現が使えます。

's/(ho)(ge)/\1:)\2/g' について

ho, geという文字をかっこでくくることにより、キャプチャを撮っています。

そして、\1, \2で再度アクセスしてます。

\1, \2の間にhappy simbolをいれてます。

mv

forとsedを組み合わせて、

sedで新しいファイル名を生成しつつ、

mvでその新しいファイル名に変更していきます。

for file in *
do
    after_file=`echo ${file} | sed -E 's/(ho)(ge)/\1:)\2/g'`
    mv -i "${file}" "${after_file}"
done

まとめ

sedコマンド、とても便利。

とくにキャプチャを取り始めるとその便利さに驚く。

今回、xargsなどを用いるともっと簡単にかけるかもしれないが、

可読性のためにココらへんでとどめておくことにした。

またチャレンジしたい。

bashは最強のポータビリティ言語。

MySQLにて、特定のカラムに日本語が含まれているかどうかを抽出

あるカラムに日本語が含まれていることを検出したい

結論

あるカラムに対して、

LENGTH

CHARACTER_LENGTH

の値が異なることを利用する。

SQLの例

SELECT
  *
FROM
  table_name
WHERE
  LENGTH(column_name) != CHARACTER_LENGTH(column_name);

解説

LENGTHは「バイト」数

LENGTH:文字列のバイト数を調べる

CHAR_LENGTHは「文字」数

なるほどねぇ。

oshiete.goo.ne.jp

sshのセキュリティ設定で、なぜポートを22から変えるとよいのか〜サーバとポートと/etc/ssh/sshd_configと〜

f:id:karoten512:20180211233659j:plain

サーバのsshdプロセスに対して、1日900回以上の不正アクセスがあった

詳しくはこの記事。

karoten512.hatenablog.com

対応方法の一つ

/etc/ssh/sshd_configを編集し、

sshdがlistenしているポートを22→10022に変える。

そもそもポートとは

サーバでは、いろんなアプリケーションが動いている

f:id:karoten512:20180211231522p:plain

nginx、sshd、mysqld、telnetdなど、

いろんなアプリケーションが動いている。

サーバを利用するときは、このアプリケーションと通信することになる。

nginxアプリケーションと通信したい時

f:id:karoten512:20180211231612p:plain

webサイトを見る場合は、この場合nginxと通信することになる。

ipアドレスによって、サーバにはたどり着くが、

これだけではnginxと通信することが出来ない。

「nginxというアプリケーションと通信したいです、とお願いすればよいのでは?」

と思うかもしれないが、ユーザ側からはサーバの中が見れないので、

webサーバがnginxなのかapacheなのか、

はたまたIISなのかはわからない。

実際は

実際、アプリケーションは「ポート」という部屋のようなものの中にいる。

(正確にはポートをlistenしている、というがわかりやすさのため部屋にいる、とした)

サーバにはポートという部屋がある

f:id:karoten512:20180211232126p:plain

サーバには、

1〜65535の番号が振られた、ポートという部屋を持っている。

それぞれの部屋にはアプリケーションが住んでいる

f:id:karoten512:20180211232310p:plain

上記のように、22番にはsshd、80番にはnginx、、、というように、

部屋の中にはアプリケーションが住んでいる。

通信するときは部屋番号を指定して通信している

f:id:karoten512:20180211232422p:plain

httpアクセスが送られる時、

サーバのipアドレス: ポート番号

という形で送られている。

これで、通信したいアプリケーションと通信ができる。

これは、マンションのある部屋に郵便物をおくるイメージと似ている。

通信は、コンピュータからコンピュータではなく、

ポートからポート、と覚えておくと良い。

アプリケーションには定められた部屋番号がある

22番にはsshd、80番にはnginxというように、

色んな人が使う可能性が高いアプリケーションは、予め決められた部屋番号がある。

これにより、

サーバの中でどんなアプリケーションが動いているかは分かんないけど、

80番ポートにアクセスしたらwebサイトみれるんじゃね?

くらいの知識でwebサービスが使える。

使う側は、ipとポートさえわかっていればよい。

「アプリケーションには定められた部屋番号がある」が逆手に取られることがある

今回、sshdに向けて不正アクセスが大量にあったのは、

f:id:karoten512:20180211233104p:plain

ハッカー「22番ポートにはsshdがすんでるハズだから、鬼ノックしてやろ!!!!」

と思った人がいたからである。

対策としては、sshdのお引っ越し

f:id:karoten512:20180211233215p:plain

こんな感じでsshdを10022番に引越ししてもらう。

(/etc/ssh/sshd_configの設定を変える)

そうすると、

ハッカーは空部屋を鬼ノックし続けるという悲しいことになる。

これでsshdへの不正アクセスがぐんと減るのだ。

まとめ

  • みんなが使うアプリケーションは、予め定められたポート番号に住まわせる

  • 他の人に使ってほしくないアプリケーションは、自分だけが知っていればよいポート番号に住まわせる

とすればよいはず。

今回ポート周りの知識が整理されたので良かった。

user「PPAP」からの不正アクセスを検出しました〜sshdのログ(/var/log/secure)から不正ユーザの名前を取り出し、セキュアじゃないユーザ名について考えてみた〜

f:id:karoten512:20180210130018j:plain

存在しないユーザからのアクセスがあった

Failed password for invalid user *** from ...

これは、

linux上で登録されていないユーザ *** からのアクセスがありました」

ということ。

今回、攻撃者がどんな名前を用いてアクセスしてくるのか

探ってみる。

手順

ログからinvalid userだけ取り出す

awkを使おう。

cat /var/log/secure | awk -F' ' '/Invalid/{print$ 8}' | sort | uniq
0
1
1111
111111
123123
1234
12345
123456
123456789
12345qwert
1234qwer
12qwaszx
1q2w3e4r
1q2w3e4r5t
1qaz2wsx
1qaz@WSX

出てきた。

ついでに集計もしてみる。

cat secure | awk -F' ' '/Invalid/{print$ 8}' | awk '{count[$0]++}END{for(i in count)print count[i], i}' | sort -nr
15 minecraft
14 www
14 user1
14 steam
14 server
14 debian

出てきた。

不正アクセス者ランキング

5位

centos: 1023件

なお、ubuntuは63件でした。

なぜubuntuじゃなくてcentosなのか。

単純にサーバとしてよく使われているから・・・?

それともnmapでOSがわかるから・・・?

(自分のサーバにnmapしてみましたが、unixという情報しか出てきませんでした)

4位

guest: 1096件

ありがち。

3位

user: 1126件

これもありがち。

2位

test: 1178件

これすごくありがち。

1位

admin: 1300件

これやったことあるな。

これからは安易に使わないようにしよう。。。

なお、6位から20位はこんな感じ。

順位回数/monthユーザ名
6112oracle
798nagios
890git
963ubuntu
1054hadoop
1152pi
1246ftpuser
1343teamspeak
1441zabbix
1541vagrant
1637vnc
1737ubnt
1835support
1931ts
2030ts3

上位5位が圧倒的すぎる。

分類

数字 + ランダムアルファベット系

0
1
1111
111111
123123
1234
12345
123456
123456789

管理者系

ADMIN
Admin123
Administrator
admin
admin1
admin123
admin2
administrador
administrator

有名人系

adam
eva

特定のクラウドサービスを狙ったもの

ec2-user

人名系

外国人

alberto
aleksei
alessandro
alex
alfresco
ali
alice
alicia
allison
ally
alma

日本人

dai
daichi
daiki
daisuke
hideaki
hideki
hideo
hikaru
hiro
hiroaki
hiroki
hiroshi
hiroyuki

ソフトウェア名

nagios
git
hadoop
nginx
nodejs
redis
vagrant

デプロイ用ユーザを狙ったと思われる系

deploy1
deploy123
deploy1234
deploy12345
deploy123456
deploy2
deploy3
deploy4
deploy5

明らかに悪意がある系

exploit

番外編

PPAP

これで日本人だと特定できたかなと思ったのもつかの間、

これ世界的に流行ったやつだからどこからアクセスされてもおかしくねえぞ。

まとめ

user名で避けるべき名前

  • admin
  • test
  • user
  • guest
  • centos

よく使われているからこそ、狙われる。

感想

割と日本人の名前が多い。

どこまで考えて攻撃しているのかはしらないけど、

安易に自分の名前をユーザ名にするのは良くないと感じた。

せめて記号や数値と織り交ぜたい。

また、ソフトウェア名も良くない。