docker-composeを使ってminioコンテナを動かす
結局、いま開発中のアプリでは利用を止めたけれど、オブジェクトストレージサーバのminioをdocker-composeで試したので内容をメモしておきます。
docker-compose.yml
gist.github.com
- ローカルマシンの9000ポートを、minioコンテナの9000ポートに紐付ける
- os ボリュームを作成して、minioコンテナの/data配下にマウント
- server /data で、オブジェクトストレージサーバをコンテナの起動時に実行させるようにして、データを/data配下に保存するようにする
- MINIO_ACCESS_KEY, MINIO_SECRET_KEYを指定してないと、ランダムな値が起動時にアサインされるので好きな値を記載して固定化させる
上記の、docker-compose.ymlファイルを含むディレクトリ内で、
docker-compose up
を実行するとminioコンテナを起動できます。
起動後、localhost:9000にブラウザなどから繋いで、MINIO_ACCESS_KEY, MINIO_SECRET_KEYの認証を通せばウェブコンソール画面が表示されるのでファイルをアップロードしたり、ダウンロードできるようになります。
package.jsonの記述を満たすようにnpmのパッケージをアップデート
ちょっと調べたことを忘れないようにブログに残しておきます。
nodejsでアプリケーションを開発していて、npmのパッケージをpackage.jsonの記述を満たす最新バージョンに更新したいことがあると思います。
例えば、package.jsonで、
"dependencies": { "mongoose": "^4.13.15", },
と記載していた場合、^の意味は、"0ではない最も左側の数字は変更しない"という意味なので、package.jsonの記述に従うmongooseのバージョンは、メジャーバージョンの4系となります。semver | npm Documentation
npm outdatedコマンドを使うと、インストールされたパッケージでバージョンが古いものを確認できます。例えば、上記のpackage.jsonを利用していた場合は以下のように出力されます。
> npm outdated Package Current Wanted Latest Location mongoose 4.13.11 4.13.15 5.2.9 xxxxxx
WantedとLatestという列が表示されていますが、Wantedには、package.jsonの記述を満たすパッケージのうち、バージョン番号が最大のものが出力されます。Latestには、レジストリにlatestのタグがつけられたバージョンのバージョン番号が出力されます。outdated | npm Documentation
mongooseのバージョンをWanted列のバージョンに更新させるには、
npm update mongoose
を実行します。
npm update mongooseの実行後、もう一度、npm outdatedを見ると、
> npm outdated Package Current Wanted Latest Location mongoose 4.13.15 4.13.15 5.2.9 xxxxxx
と出力されて、CurrentとWantedのバージョン番号が一致していることが分かります。
これで、mongooseはpackage.jsonの記述をみたす最大のバージョン番号のものに更新されました。
新卒で入社した会社を辞める
新卒で入社して、7年と3ヵ月勤めた会社を辞めました。
入社してから2~4年目、割と色々なことに関わって仕事が出来ました。5年目を過ぎたぐらいから業務内容はより細分化され、組織全体の生産性向上が進められるようになります。一人が全ての工程に関わって一台の車を作るのではなくて、工程ごとに担当を分けて車を作るようにしました。
効率的に働けるようになれば、生産性も上がり早く帰れるようになる。この変化を歓迎しました。
仕事内容は、定型化・具体化され、仕事量は減り、早く帰れるようになりました。多部署からの依頼を以前よりも早く処理出来るようになり、成果物の品質は安定するようになりました。以前よりも仕事に余裕を持つことが出来るようになり、プライベートの時間を前よりずっと取れるようになりました。
しかし、なんだか物足りない。
能力の3~4割ぐらいしか発揮してないように感じる。楽だけど記憶に残らない。2~4年目の頃がだんだん懐かしくなる。
いまの会社は決して悪い会社ではないのですが、自分の好む働き方の再現は難しくなったようです。この状況は更に進化します。
会社を辞めました。もう少し小さな組織で働こうと思います。
pythonで開発したburpエクステンションをデバッグする
burpのpythonエクステンションを作成している時に、デバッグをしたかったのでその方法を調べました。How to use pdb to debug Python Burp Extensions の内容を参考にしています。
1. registerExtenderCallbacksメソッド内に、sys.stdout, sys.stderrを追加する
以下のように、registerExtenderCallbacksメソッド内にsys.stdout, sys.stderrを追加します。import sysを忘れないように。
def registerExtenderCallbacks(self, callbacks): # debug purpose import sys sys.stdout = callbacks.getStdout() sys.stderr = callbacks.getStderr()
2. 実行を止めてデバッグしたい箇所に、import pdb; pdb.set_trace()を追加する
下記のように、ソースコードのデバッグを実行したい箇所にimport pdb; pdb.set_trace()を追加します。
# check var1 value var1 = issue.getIssueName() # stop program here import pdb; pdb.set_trace()
3. burpをコマンドラインから起動する
burpをコマンドラインから起動させます。自分の環境では、以下のパスでburpを起動することができます。burpsuite_pro.jarのパスは環境によって異なるかと思います。
java -jar /Applications/Burp\ Suite\ Professional.app/Contents//java/app/burpsuite_pro.jar
4. OutputとErrorsの向き先を"Output to system console"に変更する
開発中のエクステンションを読み込ませて、以下のようにOutputとErrorsの出力の向き先をsystem consoleに変更させます。
Output
Errors
5. エクステンションを実行してデバッグ開始
これで、デバッグの準備は出来ました。import pdb; pdb.set_trace()の箇所のソースコードが実行されるようにBurpで操作すると、コンソールからデバッグできるようになります。
~/ java -jar /Applications/Burp\ Suite\ Professional.app/Contents//java/app/burpsuite_pro.jar (Pdb) temp_val = "aaa" (Pdb) temp_val 'aaa' (Pdb) import sys (Pdb) os.name 'java'
開発が捗りますね。
JMXを利用してtomcatのJDBCコネクションプールのトラブルシューティング
セキュリティの勉強のために脆弱性のあるJavaアプリケーションを作ったのですが、スキャナをかけてしばらくするとアプリから応答が返ってこなくなります。この現象は数時間経っても変わらず、コンテナを再起動しないと直りません。
アプリケーションはローカルのdocker環境で動かしていて、
クライアントリクエスト -> apacheコンテナ -> tomcatコンテナ -> mysqlコンテナ
というフローで処理をしています。ちょっと調べてみると、tomcatコンテナまでの処理をするリクエストなら正常に返ってくるのですが、mysqlコンテナと通信する必要がある処理は応答が返ってこないことがわかりました。
ですので、原因はtomcatコンテナかmysqlコンテナにあります。さらに、mysqlコンテナ上でtcpdumpを使ってパケットはtomcatコンテナから届いているのか確認すると、何もパケットが来ていません。ということは、tomcatコンテナが正常にmysqlコンテナに接続リクエストを投げていないことが推測できます。
いろいろと調べると、tomcatコンテナにはデータベース接続プールがあり、この接続プールにあるコネクションが枯渇すると新規のリクエストがデータベースに接続出来なくなるようです。(ちょっと、細かい説明間違っているかもしれません。)ということで、tomcatのデータベースコネクションプールのコネクション数はどれぐらいあるのか確認する方法を調べました。
またまた、いろいろと調べるとJMXを利用するとtomcatのデータベースコネクションプールの様子がわかりそうです。JMXを有効にするために、docker-composeのtomcatコンテナの設定に以下を追加しました。
JMX用のポートをtomcatコンテナの9999ポートにアサインして、ローカルマシンからtomcatコンテナの9999ポートに接続できるようにしています。(ちなみに、-Djava.rmi.server.hostname=127.0.0.1を-Djava.rmi.server.hostname=0.0.0.0とするとうまくJMXに接続出来ず、一時間ぐらい悩みました。)
image: tomcat:9.0-jre9 ports: - 9999:9999 environment: CATALINA_OPTS: "-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9999 -Dcom.sun.management.jmxremote.rmi.port=9999 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.local.only=false -Djava.rmi.server.hostname=127.0.0.1"
docker-compose up でコンテナを立ち上げたあとは、ローカルマシンのターミナル上で
jconsole service:jmx:rmi:///jndi/rmi://localhost:9999/jmxrmi
を入力すればjsonsoleが立ち上がります。
使用中のデータベースコネクションの数(numActive)と、待機中のデータベースコネクションの数(numIdle)は、MBeansタブから、
Catalina => DataSource => localhost => /app => javax.sql.DataSource => jdbc_(データベース名) => connections => Attributes
と辿って行くと見つけることが出来ます。
スキャナを実行する前は、numActiveは0だったのですが、スキャナを実行してしばらくするとnumActiveは8となって、maxTotalの数8と同じになります。この状態になるとDBに接続処理のリクエストの場合は応答が返ってこなくなりました。データベース接続プールの枯渇が原因の可能性大です。
では、なぜデータベースのコネクションは解放されないのか?ソースコードを見ると、あまりJavaに詳しくないのですがなんとなく原因を特定出来ました。
問題のあるコード
InitialContext context; DataSource ds; try { context = new InitialContext(); ds = (DataSource) context.lookup("java:comp/env/xxxx"); Connection con = ds.getConnection(); Statement stmt = con.createStatement(); context.close(); String query = "select * from items where title like '%" + word + "%';"; ResultSet result = stmt.executeQuery(query); // *** skip *** // context.close(); con.close(); // *** skip *** // } catch (NamingException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); }
このアプリはセキュリティの勉強をするために作ったので、わざとSQLインジェクションが起こるように作っています。スキャナは細工したパラメータ値をリクエストで送るので、queryは正しいSQL文にならない可能性もあります。
そうすると、ResultSet result = stmt.executeQuery(query); の時点で例外を吐いて、con.close();の処理が実行されないためにコネクションが解放されていないようでした。そこで、以下のようにSQLの実行時に例外を吐いてもコネクションがcloseされるように修正しました。
修正したコード
InitialContext context; Connection con = null; DataSource ds; try { context = new InitialContext(); ds = (DataSource) context.lookup("java:comp/env/xxxx"); con = ds.getConnection(); Statement stmt = con.createStatement(); context.close(); String query = "select * from items where title like '%" + word + "%';"; ResultSet result = stmt.executeQuery(query); // *** skip *** // } catch (NamingException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } finally { if (con != null){ try { con.close(); } catch (SQLException e) { e.printStackTrace(); } con = null; } }
たぶん、まだまだ改善できるコードなんだろうなとは思いますが、この修正後、スキャナを実行してしばらくたつと応答が返ってこなくなる現象は無くなり、なんとか問題を解決することが出来ました。
vulsをvagrantのCentOS6にインストール
こちらの記事を書くときに利用した、vulsのインストール方法を共有します。
toripiyo.hatenablog.com
基本的には、Install Manually on CentOS · Vuls に記述されている方法を踏襲しています。
vagrantのCentOS6環境にvulsをローカルインストールして、自分自身に対して脆弱性スキャンをかけます。CentOS6の場合、スキャン自体はroot権限がなくても一般ユーザで実行可能です。
以下のコマンドは、CentOS6にログインして実行しています。
# install required packages sudo yum -y install sqlite git gcc make wget # install go wget https://dl.google.com/go/go1.10.1.linux-amd64.tar.gz sudo tar -C /usr/local -xzf go1.10.1.linux-amd64.tar.gz mkdir $HOME/go export GOROOT=/usr/local/go export GOPATH=$HOME/go export PATH=$PATH:$GOROOT/bin:$GOPATH/bin source /etc/profile.d/goenv.sh # deploy go-cve-dictionary sudo mkdir /var/log/vuls # change owner to be vagrant sudo chown vagrant /var/log/vuls sudo chmod 700 /var/log/vuls mkdir -p $GOPATH/src/github.com/kotakanbe cd $GOPATH/src/github.com/kotakanbe git clone https://github.com/kotakanbe/go-cve-dictionary.git cd go-cve-dictionary make install # fetch NVD data cd $HOME for i in `seq 2002 $(date +"%Y")`; do go-cve-dictionary fetchnvd -years $i; done ls -alh cve.sqlite3 # deploy goval-dictionary mkdir -p $GOPATH/src/github.com/kotakanbe cd $GOPATH/src/github.com/kotakanbe git clone https://github.com/kotakanbe/goval-dictionary.git cd goval-dictionary make install goval-dictionary fetch-redhat 6 # deploy Vuls mkdir -p $GOPATH/src/github.com/future-architect cd $GOPATH/src/github.com/future-architect git clone https://github.com/future-architect/vuls.git cd vuls make install # scan myself cat > ~/config.toml << EOF [servers] [servers.localhost] host = "localhost" port = "local" EOF vuls configtest vuls scan # check report vuls report --ovaldb-path /home/vagrant/go/src/github.com/kotakanbe/goval-dictionary/oval.sqlite3
CentOSのパッケージとセキュリティ
CentOSのパッケージのバージョンとセキュリティの関係について、いままであまりちゃんと調べてなかったので確認してそこそこまとめました。CentOS6で、CentOS公式のbaseレポジトリからphpをインストールするとphpのバージョン5.3がインストールされます。php5.3はPHPの開発元では2014年の8月14日にEOLを迎えています。
この情報のみでは、CentOS6では開発が終わっているバージョンのphpを配布しているようにみえてセキュリティ的に心配になりますが、CentOSのクローン元であるRedHatは、セキュリティの修正に対してバックポートポリシーを採用しています。
Security Backporting Practice - Red Hat Customer Portal
これはどういうことかというと、セキュリティの脆弱性が発見された際、ソフトウェアのバージョンを上げて修正するのではなくて、セキュリティの修正箇所を既存のバージョンにインポートさせるという運用のようです。こうすることで、バージョンが上がることで生じる互換性の問題を可能な限りなくしてセキュリティの穴を塞ぐことが出来ます。ということで、CentOS6のPHP5.3にもセキュリティパッチが提供されています。phpパッケージの変更履歴を見ると、php5.3がEOLを迎えた2014年8月14日以降もセキュリティの修正パッチが提供され続けていることが分かります。RedhatのRemi Colletさんが、頑張ってphpの修正パッチを当てられていることが分かります。
[vagrant@localhost ~]$ rpm -q --changelog php | head -n 20 * Mon Nov 07 2016 Remi Collet <rcollet@redhat.com> - 5.3.3-49 - fix php-soap fails to connect to HTTPS web service sporadically as stream_socket_enable_crypto() uses NONBLOCK #1283153 * Mon Jul 25 2016 Remi Collet <rcollet@redhat.com> - 5.3.3-48 - don't set environmental variable based on user supplied Proxy request header CVE-2016-5385 * Wed Dec 09 2015 Remi Collet <rcollet@redhat.com> - 5.3.3-47 - fix wrong warning in openssl_encrypt() for missing IV when IV is not required #1260315 - fix segfault's when you try and allocate an SplFixedArray with size >= 9999 #1071344 - segfault in php_pgsql_meta_data CVE-2015-4644 #1234434 - add options to enable TLS in curl #1255920 - fix segfault in gc_collect_cycles #1122681 * Fri Jul 03 2015 Remi Collet <rcollet@redhat.com> - 5.3.3-46 - fix gzfile accept paths with NUL character #1213407 - fix patch for CVE-2015-4024
Remi ColletさんはRemiパッケージのメンテナーで、remiは最新のphpパッケージなどを提供しているようです。
English : FAQ - Remi's RPM repository - Blog
CentOS6のMaintenace Updatesは、2020年11月30日まで提供されるようなので、東京オリンピックまでには余裕を持ってCentOS7に移行したいですね。
ちなみに、最近出てきた脆弱性スキャナのvulsでは、CentOS6のphpパッケージは脆弱性のあるパッケージとして誤検知されるかどうか確認してみました。vagrantでCentOS6.9の環境にvulsをインストールして自分自身をスキャンさせます。phpは最新のパッケージにしています。
toripiyo.hatenablog.com
[vagrant@localhost ~]$ rpm -qa | grep php php-common-5.3.3-49.el6.x86_64 php-5.3.3-49.el6.x86_64 php-cli-5.3.3-49.el6.x86_64 [vagrant@localhost ~]$ vuls report --ovaldb-path /home/vagrant/go/src/github.com/kotakanbe/goval-dictionary/oval.sqlite3 | head -n 20 [Jun 14 14:35:18] INFO [localhost] Validating config... [Jun 14 14:35:18] INFO [localhost] cve-dictionary: /home/vagrant/cve.sqlite3 [Jun 14 14:35:18] INFO [localhost] oval-dictionary: /home/vagrant/go/src/github.com/kotakanbe/goval-dictionary/oval.sqlite3 [Jun 14 14:35:18] INFO [localhost] Loaded: /home/vagrant/results/2018-06-13T13:01:02Z localhost (centos6.9) ===================== Total: 75 (High:24 Medium:51 Low:0 ?:0) 393 installed, 45 updatable CVE-2017-11176 10.0 HIGH (nvd) The mq_notify function in the Linux kernel through 4.11.9 does not set the sock pointer to NULL upon entry into the retry logic. During a user-space close of a Netlink socket, it allows attackers to cause a denial of service (use-after-free) or possibly have unspecified other impact. --- https://nvd.nist.gov/vuln/detail/CVE-2017-11176 https://access.redhat.com/security/cve/CVE-2017-11176 (RHEL-CVE) 10.0/AV:N/AC:L/Au:N/C:C/I:C/A:C (nvd) https://nvd.nist.gov/vuln-metrics/cvss/v2-calculator?name=CVE-2017-11176 7.8/CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H (redhat) https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator?name=CVE-2017-11176 Confidence: 100 / OvalMatch CVE-2017-18017 10.0 HIGH (nvd) The tcpmss_mangle_packet function in net/netfilter/xt_TCPMSS.c in the Linux [vagrant@localhost ~]$ vuls report --ovaldb-path /home/vagrant/go/src/github.com/kotakanbe/goval-dictionary/oval.sqlite3 2>&1 | grep -i php [vagrant@localhost ~]$
vulsではphpのパッケージは脆弱性のあるものとして誤検知されませんでした。ただ、脆弱性スキャナの中には、php-5.3.3-49.el6.x86_64のパッケージ名のphp-5.3.3の箇所のみを見て脆弱性があると判定するものもあるそうなので注意が必要です。