コピペでssl_ciphers(暗号化スイート)の指定をやってたけど、もうちょっと調べてみた
SSL Server Testで A+
判定を得るために、Generate Mozilla Security Recommended Web Server Configuration Files で生成した設定を一部利用しています。
その中でも特に目につくのが↓のなっがいやつでした。
ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK';
そもそも暗号化スイートとは?
鍵交換方式
& 鍵認証のアルゴリズム
& 共通鍵暗号アルゴリズム
& 利用するハッシュ関数
を組み合わせたものを、 暗号化スイート
と呼ぶそうです。
ssl_ciphersで先頭にきている一番のおすすめ(?) ECDHE-RSA-AES128-GCM-SHA256
を例にとってみます。
鍵交換方式(Kx)に ECDHE(楕円曲線ディフィー・ヘルマン鍵共有 - Wikipedia - Elliptic curve Diffie–Hellman key exchange)を使う
Kxは「安全でない経路で結ばれたサーバとクライアント間で共通鍵を安全に交換する」という目的を達するための仕組み。公開鍵暗号の鍵交換を担う
サーバ認証のアルゴリズム(Au)にRSA 実際に通信する相手が、証明書の持ち主か認証するための仕組み。
公開鍵暗号の署名を担う
暗号化の方法(Enc)に
AES&GCM
共通鍵を使用して暗号化通信する際の方式。共通鍵を交換し終わったあと実際に情報をやり取りする際の暗号化・復号化を担う
で、いいのかな。KxとAuの役割の違いがよくわからんくなった。
結論
最新の 鍵交換方式
& 鍵認証のアルゴリズム
& 共通鍵暗号アルゴリズム
& 利用するハッシュ関数
を全部追っかけとかないといこうとすると辛いなーと思った。
何も考えずにコピペしない、という前提のもと Generate Mozilla Security Recommended Web Server Configuration Files などを参考に、内容を理解し、自身の環境に適用できるか検討したうえで選択する、というのが現実的なところか…
ちなみに
ssl_ciphers
で完璧なものを指定しておけば安心!というわけではない(最近おしえてもらった)
ssl_prefer_server_ciphers on;
でサーバ側の暗号化スイート設定を優先するようにしておかないと、クライアント側の設定が利用されて辛いssl_session_tickets off;
デフォは有効なので、使わないのであれば明示的にoff
にする。(クラスタ構成にする場合は、複数台のnginxでsession cacheを共有するため有効にし、定期的にkeyの更新を行わせる必要がある。nginx.confssl_session_ticket_key /etc/nginx/ticket.key;
とファイルを明示し、cronなどでopenssl rand 48 > /etc/nginx/tickets.key
で定期更新し、各nginxで同じものを使う。ssl_session_timeout 5m;
有効期限が短ければ短いほど、安全なはず。サーバ負荷と相談しつつ設定- nginx外のそもそものサーバ設定。ミドルウェアの設定を頑張ってもfirewallが全空きでした!じゃ辛い
とても良い記事 qiita.com
Let's Encryptを使用したkame.photosのSSL Server Test結果をA+にした
参考
- 細かすぎて伝わらないSSL/TLS - Yahoo! JAPAN Tech Blog
- Generate Mozilla Security Recommended Web Server Configuration Files
- SSL Server Test: kame.photos (Powered by Qualys SSL Labs)
- NginxでSSLの評価をA+にする手順 - 9mのパソコン日記
- 我々はどのようにして安全なHTTPS通信を提供すれば良いか - Qiita
http { 〜略〜 # HTTP Strict Transport Security の指定。サブドメインにも適用 add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains;'; 〜略〜 server { listen 443 ssl http2; # プロトコルはTLS1.2に限定 ssl_protocols TLSv1.2; # TLSセッションキャッシュ有効期限 ssl_session_timeout 5m; # TLSセッションキャッシュを全ワーカプロセスで共有。サイズは50MB ssl_session_cache shared:SSL:50m; # DH鍵交換のパラメータファイルの指定「openssl dhparam 2048 -out dhparam.pem」で生成 ssl_dhparam /etc/nginx/dhparam.pem; # 暗号化スイート指定(MozillaConfigGenerator参照) ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK'; # サーバサイドの暗号化スイート指定を優先 ssl_prefer_server_ciphers on; # TLSセッションチケットはOFF - TLSセッションキャッシュはsession resumptionを使う ssl_session_tickets off; # OCSP Staplingを有効化にする ssl_stapling on; ssl_stapling_verify on; # 認証局の証明書 ssl_trusted_certificate /etc/letsencrypt/live/kame.photos/ce-cert; ssl_certificate /etc/letsencrypt/live/kame.photos/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/kame.photos/privkey.pem; 〜略〜
いろいろと気にするところがあるのだな〜とおもた
cclogconv(IPアドレスから国名を取得するツール)を使ってみた
???
[PMAC226S ~/src/github.com/rhykw/cclogconv]$ echo "111.169.213.70" | cclogconv --data ./GeoLite2-Country.mmdb JP 111.169.213.70
とりあえずtmp直下にDBはおくように設定してビルド
[PMAC226S ~/src/github.com/rhykw/cclogconv]$ git diff diff --git a/cclogconv.go b/cclogconv.go index e4bf4da..883fc76 100644 --- a/cclogconv.go +++ b/cclogconv.go @@ -15,7 +15,7 @@ import ( func main() { var ( - optMmdbFilePath = flag.String("data", "/usr/share/GeoIP2/GeoLite2-Country.mmdb", "GeoIP2 Database Filename") + optMmdbFilePath = flag.String("data", "/tmp/GeoLite2-Country.mmdb", "GeoIP2 Database Filename") selectCc = flag.String("cc", "", "Only displays line including this country's ip") nFlag = flag.Bool("n", false, "Not adding country code") vFlag = flag.Bool("v", false, "Reverse condition for cc option")
cd /tmp curl -O http://geolite.maxmind.com/download/geoip/database/GeoLite2-Country.mmdb.gz gunzip GeoLite2-Country.mmdb.gz
準備OK
使う
- 未使用時
[PMAC226S ~/src/github.com/rhykw/cclogconv]$ tail -10 access.log 66.249.71.213 - - [29/Jan/2016:21:47:09 +0900] "GET /feed/ HTTP/1.1" 404 168 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" 17.142.156.142 - - [29/Jan/2016:21:53:00 +0900] "GET / HTTP/1.1" 200 15817 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/600.2.5 (KHTML, like Gecko) Version/8.0.2 Safari/600.2.5 (Applebot/0.1; +http://www.apple.com/go/applebot)" 66.249.71.213 - - [29/Jan/2016:21:56:09 +0900] "GET /%E3%81%8B%E3%82%81%E3%83%95%E3%83%BC%E3%83%89%E5%A5%BD%E3%81%8D%E4%B8%89%E4%BA%BA%E8%A1%86/ HTTP/1.1" 404 168 "-" "Mozilla/5.0 (iPhone; CPU iPhone OS 8_3 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12F70 Safari/600.1.4 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" 157.55.39.71 - - [29/Jan/2016:21:56:21 +0900] "GET /robots.txt HTTP/1.1" 404 168 "-" "Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)" 157.55.39.71 - - [29/Jan/2016:21:56:26 +0900] "GET / HTTP/1.1" 200 15828 "-" "Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)" 185.130.5.244 - - [29/Jan/2016:22:20:26 +0900] "GET /phpmyadmin/scripts/setup.php HTTP/1.0" 404 16 "-" "-" 66.249.71.252 - - [29/Jan/2016:22:26:35 +0900] "GET /?cat=11 HTTP/1.1" 200 15992 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" 157.55.39.71 - - [29/Jan/2016:22:59:20 +0900] "GET /%e3%82%ad%e3%83%9c%e3%82%b75/ HTTP/1.1" 404 168 "-" "Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)" 66.249.71.234 - - [29/Jan/2016:23:14:35 +0900] "GET /?m=201509 HTTP/1.1" 200 16072 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" 184.105.139.68 - - [29/Jan/2016:23:22:49 +0900] "GET / HTTP/1.1" 200 15828 "-" "-"
- かませてみる
[PMAC226S ~/src/github.com/rhykw/cclogconv]$ tail -10 access.log | ./cclogconv US 66.249.71.213 - - [29/Jan/2016:21:47:09 +0900] "GET /feed/ HTTP/1.1" 404 168 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" US 17.142.156.142 - - [29/Jan/2016:21:53:00 +0900] "GET / HTTP/1.1" 200 15817 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/600.2.5 (KHTML, like Gecko) Version/8.0.2 Safari/600.2.5 (Applebot/0.1; +http://www.apple.com/go/applebot)" US 66.249.71.213 - - [29/Jan/2016:21:56:09 +0900] "GET /%E3%81%8B%E3%82%81%E3%83%95%E3%83%BC%E3%83%89%E5%A5%BD%E3%81%8D%E4%B8%89%E4%BA%BA%E8%A1%86/ HTTP/1.1" 404 168 "-" "Mozilla/5.0 (iPhone; CPU iPhone OS 8_3 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12F70 Safari/600.1.4 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" US 157.55.39.71 - - [29/Jan/2016:21:56:21 +0900] "GET /robots.txt HTTP/1.1" 404 168 "-" "Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)" US 157.55.39.71 - - [29/Jan/2016:21:56:26 +0900] "GET / HTTP/1.1" 200 15828 "-" "Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)" LT 185.130.5.244 - - [29/Jan/2016:22:20:26 +0900] "GET /phpmyadmin/scripts/setup.php HTTP/1.0" 404 16 "-" "-" US 66.249.71.252 - - [29/Jan/2016:22:26:35 +0900] "GET /?cat=11 HTTP/1.1" 200 15992 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" US 157.55.39.71 - - [29/Jan/2016:22:59:20 +0900] "GET /%e3%82%ad%e3%83%9c%e3%82%b75/ HTTP/1.1" 404 168 "-" "Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)" US 66.249.71.234 - - [29/Jan/2016:23:14:35 +0900] "GET /?m=201509 HTTP/1.1" 200 16072 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" US 184.105.139.68 - - [29/Jan/2016:23:22:49 +0900] "GET / HTTP/1.1" 200 15828 "-" "-"
使いみち
たとえば、便利だと思うのが中国からきてるIPをまるっと弾きたいとき
[PMAC226S ~/src/github.com/rhykw/cclogconv]$ cat access.log | ./cclogconv | grep '^CN' | awk '{print $2}' | sort | uniq 101.254.204.65 171.214.248.34 180.76.15.13 180.76.15.135 180.76.15.136 180.76.15.137 180.76.15.141 180.76.15.143 180.76.15.147 180.76.15.155 180.76.15.157 180.76.15.162 180.76.15.17 180.76.15.19 180.76.15.22 180.76.15.31 180.76.15.6 180.97.106.161 202.46.50.12 222.191.236.114
かんたんに取り出せる。
シェルスクリプトで巨大な文字列とのマッチング処理をするとき、変数格納よりもファイル参照したほうが速かった
この前必要があってお粗末なスクリプトを書いた時、速度に大きな差があったので気になった。
なんとなく変数に持ったほうが、試行回数が増えるほど早くなるのかとおもってた
宣伝
今回の環境
KagoyaVPS 最小構成CentOS6.5 日毎課金なので特にこだわりなければ安くあがっておすすめです。ちょっと触ってすぐ削除するような使い方
[root@v8794 work]# cat /proc/cpuinfo | grep processor processor : 0 processor : 1 processor : 2 [root@v8794 work]# cat /etc/redhat-release CentOS release 6.5 (Final) [root@v8794 work]# free total used free shared buffers cached Mem: 2097152 445288 1651864 0 0 424992 -/+ buffers/cache: 20296 2076856 Swap: 4194304 21420 417288
使用するファイル
- 巨大テキスト 以下で取得したデータを変換して作成 私立PDD図書館/百科辞書
# ファイルに対してgrep [root@v8794 work]# cat file.sh #! /bin/sh cat << EOF | while read txt `cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 16 | head -n $2 | sort | uniq` EOF do grep ${txt} $1 if [ $? -eq 0 ]; then echo "true" else echo "false" fi done # 変数に格納したあとgrep [root@v8794 work]# cat val.sh #! /bin/sh testtxt=`cat $1` cat << EOF | while read txt `cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 16 | head -n $2 | sort | uniq` EOF do echo $testtxt | grep ${txt} if [ $? -eq 0 ]; then echo "true" else echo "false" fi done
ファイル観たほうが速い
[root@v8794 work]# time ./file.sh test.txt 10 false false false false false false false false false false real 0m0.179s user 0m0.087s sys 0m0.085s [root@v8794 work]# time ./val.sh test.txt 10 false false false false false false false false false false real 0m51.921s user 0m45.767s sys 0m7.232s
ちなみに、小さいファイルにしたら逆転するのかと思ったら、そんなことなかった
[root@v8794 work]# ll test2.txt -rw-r--r-- 1 root root 17000 1月 23 20:48 2016 test2.txt [root@v8794 work]# time ./file.sh test2.txt 10 false false false false false false false false false false real 0m0.019s user 0m0.002s sys 0m0.007s [root@v8794 work]# time ./val.sh test2.txt 10 false false false false false false false false false false real 0m0.049s user 0m0.032s sys 0m0.008s [root@v8794 work]
あれ?これって当たり前の話??? もしかして恥ずかしい疑問なのかもしれない
最近便利だと思ってよく使うコマンドとか
すぐ忘れるので備忘録
コマンドの実行結果を一時ファイルを作成せずにdiffる
[root@v8794 nginx]# diff -u nginx.conf <(sed 's/kame/hoge/g' nginx.conf) --- nginx.conf 2016-01-17 18:04:41.000000000 +0900 +++ /dev/fd/63 2016-01-23 00:43:56.601767533 +0900 @@ -9,17 +9,17 @@ keepalive_timeout 65; server { listen 80; - server_name kame.photos; + server_name hoge.photos; location / { - root /var/www/kame; + root /var/www/hoge; index index.php; } location ~ \.php$ { - root /var/www/kame; + root /var/www/hoge; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; - fastcgi_param SCRIPT_FILENAME /var/www/kame$fastcgi_script_name; + fastcgi_param SCRIPT_FILENAME /var/www/hoge$fastcgi_script_name; include fastcgi_params; } @@ -31,19 +31,19 @@ ssl_protocols TLSv1.2; #ssl_session_timeout 5m; - ssl_certificate /etc/letsencrypt/live/kame.photos/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/kame.photos/privkey.pem; + ssl_certificate /etc/letsencrypt/live/hoge.photos/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/hoge.photos/privkey.pem; location / { - root /var/www/kame; + root /var/www/hoge; index index.php; } location ~ \.php$ { - root /var/www/kame; + root /var/www/hoge; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; - fastcgi_param SCRIPT_FILENAME /var/www/kame$fastcgi_script_name; + fastcgi_param SCRIPT_FILENAME /var/www/hoge$fastcgi_script_name; include fastcgi_params; }
<( command )
の結果に /dev/fd/63
とファイルディスクリプタが割り当てられている
↑を応用して、find&replaceの確認
たとえば、あるディレクトリ以下のphpでおわるファイルの中身を wp
-> KAME
に変更する際に、想定のファイルが想定の部分だけ変更されるか、をチェックする。
[root@v8794 widgets]# for x in `find . -type f`; do diff -u $x <(sed 's/wp/KAME/g' $x); done --- ./class-wp-widget-calendar.php 2015-09-27 10:07:25.000000000 +0900 +++ /dev/fd/63 2016-01-23 01:24:20.132003630 +0900 @@ -48,7 +48,7 @@ * @param array $instance The settings for the particular instance of the widget. */ public function widget( $args, $instance ) { - /** This filter is documented in wp-includes/widgets/class-wp-widget-pages.php */ + /** This filter is documented in KAME-includes/widgets/class-KAME-widget-pages.php */ $title = apply_filters( 'widget_title', empty( $instance['title'] ) ? '' : $instance['title'], $instance, $this->id_base ); echo $args['before_widget']; @@ -94,7 +94,7 @@ * @param array $instance Current settings. */ public function form( $instance ) { - $instance = wp_parse_args( (array) $instance, array( 'title' => '' ) ); + $instance = KAME_parse_args( (array) $instance, array( 'title' => '' ) ); $title = sanitize_text_field( $instance['title'] ); ?> <p><label for="<?php echo $this->get_field_id('title'); ?>"><?php _e('Title:'); ?></label> --- ./class-wp-nav-menu-widget.php 2015-09-29 00:31:25.000000000 +0900 +++ /dev/fd/63 2016-01-23 01:24:20.134003626 +0900 @@ -39,12 +39,12 @@ */ public function widget( $args, $instance ) { // Get menu - $nav_menu = ! empty( $instance['nav_menu'] ) ? wp_get_nav_menu_object( $instance['nav_menu'] ) : false; + $nav_menu = ! empty( $instance['nav_menu'] ) ? KAME_get_nav_menu_object( $instance['nav_menu'] ) : false; if ( !$nav_menu ) return; - /** This filter is documented in wp-includes/widgets/class-wp-widget-pages.php */ + /** This filter is documented in KAME-includes/widgets/class-KAME-widget-pages.php */ $instance['title'] = apply_filters( 'widget_title', empty( $instance['title'] ) ? '' : $instance['title'], $instance, $this->id_base ); echo $args['before_widget']; @@ -64,7 +64,7 @@ * @since 4.4.0 Added the `$instance` parameter. * * @param array $nav_menu_args { - * An array of arguments passed to wp_nav_menu() to retrieve a custom menu. + * An array of arguments passed to KAME_nav_menu() to retrieve a custom menu. * * @type callable|bool $fallback_cb Callback to fire if the menu doesn't exist. Default empty. * @type mixed $menu Menu ID, slug, or name. @@ -73,7 +73,7 @@ * @param array $args Display arguments for the current widget. * @param array $instance Array of settings for the current widget. */ - wp_nav_menu( apply_filters( 'widget_nav_menu_args', $nav_menu_args, $nav_menu, $args, $instance ) ); + KAME_nav_menu( apply_filters( 'widget_nav_menu_args', $nav_menu_args, $nav_menu, $args, $instance ) ); echo $args['after_widget'];
同じパターンのファイルを大量に生成する
cat << EOF > xxx.txt
や cat << EOF | command1 | command2
が、一時ファイルを用意せず色々やれてすき
[root@v8794 sample]# for x in `seq 1 100`; do cat << EOF | sed "s/_PLACEHOLDER_/for_${x}_replace/g" > work/${x}.txt <html> <head>_PLACEHOLDER_</head> <body> _PLACEHOLDER_XXXXXXXXXXXXXXXXXXXXX </body> </html> EOF ; done [root@v8794 sample]# ls -lt work/ 合計 400 -rw-r--r-- 1 root root 109 1月 23 01:02 2016 1.txt -rw-r--r-- 1 root root 109 1月 23 01:02 2016 10.txt -rw-r--r-- 1 root root 109 1月 23 01:02 2016 100.txt -rw-r--r-- 1 root root 109 1月 23 01:02 2016 11.txt -rw-r--r-- 1 root root 109 1月 23 01:02 2016 12.txt -rw-r--r-- 1 root root 109 1月 23 01:02 2016 13.txt -rw-r--r-- 1 root root 109 1月 23 01:02 2016 14.txt -rw-r--r-- 1 root root 109 1月 23 01:02 2016 15.txt -rw-r--r-- 1 root root 109 1月 23 01:02 2016 16.txt -rw-r--r-- 1 root root 109 1月 23 01:02 2016 17.txt -rw-r--r-- 1 root root 109 1月 23 01:02 2016 18.txt -rw-r--r-- 1 root root 109 1月 23 01:02 2016 19.txt -rw-r--r-- 1 root root 109 1月 23 01:02 2016 2.txt -rw-r--r-- 1 root root 109 1月 23 01:02 2016 20.txt [root@v8794 sample]# cat work/1.txt <html> <head>for_1_replace</head> <body> for_1_replaceXXXXXXXXXXXXXXXXXXXXX </body> </html>
予め定められたリストにマッチした場合に、規定値を使用して処理する
#! /bin/sh DATA=" 01 AAAAAAAAAAAAAAAAA tanaka 02 BBBBBBBBBBBBBBBBB ikeda 03 CCCCCCCCCCCCCCCCC yamada " d=$(echo "${DATA}" | grep $1) read no txt user <<< "${d}" echo $no echo $txt echo $user
量が多くなるのであればDBなど使用するほうがよいが、小さなプログラムに便利。
read x y z <<< $val
もすき。