Quantcast
Channel: Cybozu Inside Out | サイボウズエンジニアのブログ
Viewing all 681 articles
Browse latest View live

サマーインターンサイトのアクセシビリティ対応の裏話

$
0
0

こんにちは、デザイングループ所属の小林です。サイボウズのサービスや製品に関するアクセシビリティ対応をしています。

先日、サイボウズはサマーインターンのWebサイトを公開しました。 このサイト、実はWebアクセシビリティについて、さまざまな配慮をしながらデザインやマークアップを行なっています。今回はその制作裏話をしようと思います。

サイボウズサマーインターンWebサイトの表紙

なぜアクセシビリティ対応?

サイボウズでは、アクセシビリティを「ユーザがチームにアクセスできる能力」と定義してアクセシビリティの取り組みを進めています。

理想的には、サイボウズが制作しているすべてのWebサイトや製品、サービスについてアクセシビリティの配慮が行われることが望ましいですが、いきなり規模の大きい既存のWebサイトのアクセシビリティを改善するのは大きなコストがかかります。また、デザイナーやエンジニアのアクセシビリティに関するスキルも、一朝一夕に身につくものではありません。

そこで、まずは規模が小さく新規に作成するページについて、少しずつアクセシビリティに考慮することで、今後のサイトの改善のヒントを得ながら、一人ひとりのスキルを高めていこうということになりました。サマーインターンサイトは、1ページのみ、かつ新規につくるページだったので、目的に合致していました。

制作体制

サマーインターンサイトは、数名のデザイナーが人事やメンターと一緒に制作しました。制作中の成果物に対して、自分がアクセシビリティの観点から数回レビューを行い、各デザイナーに問題点や改善方法をフィードバックしました。

アクセシビリティレビュー

今回、アクセシビリティについては、以下のような観点を考慮して、チェックや改善を行いました。

色のコントラスト比

ロービジョンのユーザや、屋外で日光があたる環境などでは、コントラスト比の低い色同士を区別することが難しい場合があります。アクセシビリティの国際基準であるWeb Content Accessibility Guideline 2.0(WCAG 2.0)には、文字色と背景色のコントラスト比を一定値以上にせよ、という基準があります。

もともと「エントリー」ボタンについては、WCAG2.0の基準を満たしていませんでした。また、ボタンにマウスホバーをしたときには、コントラスト比がさらに低くなるデザインになっていました。デザイナーに相談し、マウスホバーする前後どちらでも、コントラスト比の基準を満たすように色を修正しました。

以下の画像は、修正前のエントリーボタンです:

修正前のエントリーボタン

以下の画像は、修正後のエントリーボタンです: 修正後のエントリーボタン

キーボードによる操作

マウスを使うことが難しいユーザにとっては、代替手段として、キーボードでマウスと同等の操作ができることが重要です。

当初のデザインでは、キーボード操作したときのインジケータがCSSで消されており、 キーボードでどこを操作したのかがわからない状態だったので、インジケータを復活させました。

以下の画像は、Chromeでページ内のテキストリンクにキーボードフォーカスしたときの様子です。 ここにはブラウザデフォルトのインジケータが表示されるデザインにしています。Chromeでは水色のインジケータが表示されます: Chromeでテキストリンクにキーボードフォーカスした様子

また、「募集要項」のボタンをクリックした時に表示されるダイアログは、当初LeanModalというライブラリを使って実装していましたが、 LeanModalはキーボード操作の対応が不十分で、ダイアログの裏側の要素にフォーカスすることができてしまっていました。 これではマウスで操作できない部分をキーボードで操作できてしまいます。

キーボード操作に対応しているライブラリを探したところ、BootstrapのModalが対応できていたので、 ライブラリを変更し、ダイアログを開いているときには、ダイアログの裏側にフォーカスがあたらないようにしました。

ダイアログのマークアップ

BootstrapのModalに関する文書には、アクセシビリティに関するポイントがまとめられています。 この文書には、ダイアログのマークアップについて、以下のように記載されています:

  • role=“dialog"をつける
  • aria-labelledby=“…"に、ダイアログのタイトル部分のIDを指定する
  • aria-describedby=“…"に、ダイアログのボディ部分のIDを指定する

これらの属性をつけることで、ダイアログを開いた時に、スクリーンリーダーが、ダイアログのタイトルやボディを読み上げます。デザイナーにマークアップの意味を説明し、各属性を追加しました。

画像の代替テキスト

当初、メンターの画像にはalt属性を使った代替テキストとしてメンターの名前がついていました。この指定方法でも大きな問題はありませんが、スクリーンリーダーなどで読み上げた際には、メンターの名前が二重で読み上げられることになります。今回は読み上げの冗長さを解消するため、画像のalt属性には空文字を指定するようにしました。

メンターの紹介のスクリーンショット。メンターの画像の下にメンターの名前、所属、FacebookとTwitterのリンクが書かれている。

アイコンフォント

「メンター」セクションのFacebookとTwitterのアイコンには、Font Awesomeが使われています。これらのアイコンは当初、以下のようにマークアップされていました。

<a href="..." target="_blank">
  <i class="fa fa-facebook-official fa-lg" aria-hidden="true"></i>
</a>

この実装では、アイコンにラベルがついていないため、 スクリーンリーダーなどでアイコンを読み上げようとしても、読み上げが行われません。

Font AwesomeのAccessibilityに関するページには、aria-labelを使ってラベルをつけるように指示されています。 これをデザイナーに伝え、アイコンフォントにはラベルをつけるようにしました。

<a href="..." target="_blank" aria-label="facebook">
  <i class="fa fa-facebook-official fa-lg" aria-hidden="true"></i>
</a>

レビューの効果

自動チェックツールによるエラーが0個に!

今回は、aXeというアクセシビリティ自動チェックツール(Chrome拡張)を導入し、 上記に挙げた以外にも、様々なデザインやマークアップの修正を行いました。 最終的に、aXeによるアクセシビリティエラーや警告の検出数を0個にすることができました。

aXeの自動テストでエラーが0個になった状態をChromeの開発コンソールで確認する様子。

デザイナーのスキルアップ

デザイナーのスキルも向上しました。例えば、「概要」の会社の「場所」につけられた地図アイコンは、 Font Awesomeで実装しましたが、デザイナー自ら、aria-labelをつけてくれるようになりました。

<a href="https://cybozu.co.jp/company/access/#tokyo" target="_blank" aria-label="地図">
  <i class="fa fa-map-marker fa-lg" aria-hidden="true"></i>
</a>

デザイナーに修正をお願いするときのポイント

できるだけ公式情報を参照する

デザイナーに修正をお願いするときは、個人のブログやTipの紹介等のページを参照することはできるだけ避けました。 個人のブログなどで紹介されている技術情報の中には、アクセシビリティに配慮されていないものがあったり、一部の障がいや環境のみを取り上げて解説している場合があるためです。 また、場当たり的な内容を伝えているという印象を与えかねないことも懸念のひとつでした。

代わりに、W3Cの提供しているページや、Font Awesome、Bootstrapの公式サイトを参照するようにし、標準的な対応であることを強調しました。 この方法は、スキルアップを望んでいるデザイナーからも好評でした。

デザイナーとのやりとり。デザイナー「小林大輔さんのアクセシビリティの話はホント勉強になるなぁ。今まで作ったサイトも見直そーっと」と書かれている。

スクリーンリーダーで効果を説明する

マークアップの修正の中には、ビジュアルブラウザのみでは、効果が確認しづらい内容もありました。 スクリーンリーダーを使って実際にサイトを読み上げながらマークアップの違いをデザイナーに伝えることで 修正がどのような影響をもたらすのか、理解の手助けになりました。

サマーインターンでアクセシビリティの講義を受けませんか?

サイボウズでは、サマーインターンの参加者を募集しています。 サマーインターン期間中には、アクセシビリティの講義を開催する予定です。 より詳しくアクセシビリティの話をきいてみたい、アクセシビリティに関してスキルアップしたいという方は是非エントリーしてみてください。

エントリーをお待ちしています!


「サイボウズにスクラムを導入した話」を肴にミートアップ!

$
0
0

こんにちは、コネクト支援チームの風穴(かざあな)です。

早いもので、2017年の半分が過ぎようとしていますが、皆さん、進捗はいかがですか?(笑) それはさておき、今回は、5月30日に開催した「Cybozu Meetup #4 スクラム」についてレポートします。

f:id:cybozuinsideout:20170612173645j:plain

サイボウズのミートアップ

2017年2月からスタートしたこの企画も、今回で4回目となりました。

改めておさらいしますと、「Cybozu Meetup」は、サイボウズのエンジニアとカジュアルに交流する場として企画、開催しているイベントシリーズです。会場はサイボウズのオフィスなので、社内の雰囲気や社員の様子を、実際に肌で感じて頂ける機会でもあります。

今のところ、東京オフィスで月1回、大阪オフィスで数カ月に1回のペースで、開催していこうと考えています。毎回テーマを設定していて、これまで「フロントエンド」、「SRE」(Site Reliability Engineering)、「生産性向上」というネタで開催してきました。

サイボウズのスクラム/アジャイル

第4回のテーマは「スクラム/アジャイル」。

サイボウズでは、1年ほど前から、開発チームへのスクラム導入を本格的に進めています。その旗振り役となっている、kintone開発チームリーダーの天野 祐介(@ama_ch)が、

  • スクラム導入前に抱えていた課題
  • スクラム導入の経緯
  • 導入期の試行錯誤
  • 現在のやり方

について発表しました。

f:id:cybozuinsideout:20170612173720j:plain

公開したスライドからは除いてますが、当日のトークセッションでは、公開できない 生々しい情報(=撮影禁止)もお見せしながら、サイボウズのこれまでの取り組みについて、お話しさせていただきました。こういうところは「ライブならでは」ですので、ご興味がありましたら、ぜひ一度、Cybozu Meetupに足をお運び頂ければ。

質問&交流タイム

トークセッションの後の交流タイムでは、スクラムを導入している開発チームのエンジニアや一般社員も参加し、スクラム話に花が咲きました。

f:id:cybozuinsideout:20170612173757j:plainf:id:cybozuinsideout:20170612173836j:plain

サイボウズでは、今後も開発チームへのスクラム導入を積極的に進めていくことになっており、スクラムマスターとして活躍してくださる方を大募集しています。詳細は、以下のWantedlyのページをご覧ください。

求む、スクラムマスター! 開発をさらに加速させるチャレンジ

7月以降も、毎月開催を予定しています。ご興味ある方は、connpassグループ「Cybozu Inside Out」をフォローして、情報をチェック頂ければ。

ではまた。

プロジェクト引き継ぎのベストプラクティス、そしてアンチパターン

$
0
0

あじさいがきれいですね。そんなことを可愛い女の子に言ってみたい。

どうも!アプリ基盤チームの@yokotasoです。

唐突ですが、プロジェクトの引き継ぎはうまく行っていますか?

プロジェクトの引き継ぎを経験すると、「あのとき聞いておけばよかった…」経験あると思います。

社内でためた引き継ぎの知見を公開します!どうぞ!

開発のハードルを下げるための引き継ぎ

開発環境をコンテナ化する

人の移動が多くないプロジェクトでは、開発環境構築のドキュメントが長い間メンテナンスされないことがあります。 この手のプロジェクトを引き継ぐことになったら、最初に検討すべきは開発環境のコンテナ化です。

コンテナの内部でできるだけ作業が完結するように、依存するライブラリやパッケージはすべてコンテナの中に収めましょう。 動作確認もWebサービスであればコンテナ内にWebブラウザーをインストールし作業がコンテナ内で完結することを目指します。

コンテナ化すると嬉しいこと

  • 他の開発メンバーも参加しやすくなる
  • コンテナ化すれば、環境をコードで表すことができ、利用者がパッチを投げてくれる
  • 既存の開発環境を汚染しない

利用ライブラリのバックアップを忘れずに

開発時に必要なものはダウンロード可能な状態を維持するために、バックアップをしておきましょう。 本家のレポジトリが突然消えたりなど、なんらかのアクシデントでアーカイブがダウンロード不能になったりすることがあります。

CIシステムの引き継ぎ

CIシステムに関する引き継ぎもしましょう。スムーズにリリースできる仕組みを維持していく必要があります。

CIシステムが、突然動かなくなる可能性はあります。

  • CIシステムが不安定になるときの特徴、対処方法などを引き継ぎましょう。
  • 時間があるときに根本的な原因の究明を行うようにしましょう。

「いつか成功する」は圧倒的アンチパターンなので、撲滅していきましょう

問題の解決が難しい場合、監視など問題の発生に早く気付けるような仕組みを構築するのもよいでしょう。 CIシステム自体の問題に早く気付けるようになることで、問題の切り分けが容易になり調査のストレスを減らせます。

できるだけCI環境を停止するのはやめましょう。CIを復旧するのにそれ相応のストレスが伴います。

外部サービス連携の引き継ぎ

外部サービスの認証情報の切り替え

開発で利用している外部サービスの認証情報は、前任者がいるうちに利用しているアクセストークンの入れ替えなどを行っておきます。 前任者の退職に伴いアクセストークンの有効期限切れになり、連携している外部サービスがうまく動かなくなることがよくあります

引き継ぎ失敗あるある

  • 引き継ぎ完了後、JenkinsからGitHubのCommit StatusのAPIの実行に失敗する
  • テストは成功するが、Git Hubのステータス更新がされない
  • Git Hubのアクセストークンの更新を忘れていた

アクセストークンが有効なうちはPull Requestからアクセストークンの発行主を確認することができるので確認しておきましょう

f:id:cybozuinsideout:20170621115619p:plain

APNs の証明書の発行フローを確認する

Push通知を利用している場合、証明書の更新が1年に1回程度は必要になります(JWTを用いた認証方式を除く)。 証明書の更新が要求される外部サービスはかならず引き継ぐようにしましょう。

証明書管理のベストプラクティス

  • プロジェクトメンバーが複数人、証明書にアクセスできる状態を作る
  • 証明書の期限切れを3ヶ月ほど前にチームに対してリマインドする
  • 証明書の更新を優先度の高いタスクとして登録する

f:id:cybozuinsideout:20170621145909p:plain弊社ではグループウェアのスケジュール上にリマインド予定を登録しています

開発者用アカウントの整備

Facebook,Twitterなど外部サービスと連携する場合は開発者用アカウントを整備しましょう。動作確認用に必要なアカウントを用意しましょう。 外部連携サービスの動作確認のハードルを下げることができます。

チームで共通アカウントを利用する場合は、どこかで一元管理すると良いでしょう。

共通アカウント管理のルールの例

  • 開発者用アカウントにアクセスできるのは、アクセス権をもつチームメンバーのみ
  • 情報システム部にパスワードを定期的に変更するリマインドをしてもらうルールを作る

外部連携APIのメンテナンス

「Facebookでログイン」など外部サービスのAPIと連携している場合、APIの期限切れに警戒しましょう。期限切れの半年前などにリマインドを設定しておくと安心です。 特にFacebookAPIは、APIの賞味期限が短いです。新しいversionが頻繁にリリースされていきます。

外部連携APIについてドキュメント化する

  • 利用APIを明記する
  • 動作確認方法を明記
  • 利用APIの期限切れをチームに対してリマインドする

バッチ処理などでFacebook APIを使うと、動作確認ミスが起きやすくなります。このあたりは注意が必要です

version無指定のAPI利用はアンチパターン

Facebook APIではversionを指定しない利用方法もあります。この場合、利用可能なAPIのうち一番古いversionのAPIが利用されることになります。 一見、便利な機能です。Facebookからも警告が届きます。ですが、version無指定が常態化するとFacebookの警告は、無視するようになるでしょう。 Facebook APIの仕様変更に気付けずログインができないなどの致命的なバグに繋がります。

version指定をしてAPIを利用しましょう

ライブラリへの独自パッチの適用を引き継ぎ

f:id:cybozuinsideout:20170621133108p:plain

レガシーなプログラムほど、既存のライブラリでは要求を満たすことができず、独自パッチが適用されていることが多いです。 ハックはビジネス的な価値を提供する一方で、メンテナンス性を悪化させます。

引き継ぎの担当者は独自改修の存在に気付けるようになっているでしょうか?レガシー・ブラウザ対応のための独自パッチは未だに必要でしょうか?

  • 独自パッチを適用するときは、適用した理由と箇所、ビジネス的な価値を必ずドキュメント化する
  • 止むを得ず独自パッチを適用しているときは、ライブラリのアップデート時にハックが外せないかを調査する
  • ビジネス的な価値を失った不要な独自パッチはは積極的にもとに戻す

サービス運用にまつわる引き継ぎ

メトリクスの共有

サービスに障害が発生している時にいつも見ているメトリクスは共有しておきましょう。 メトリクスがなければ、障害が発生しても何がおきているのか、わかりません。

メトリクスにあわせて、障害が発生するときの特徴的な負荷状況を共有しておきましょう。

いつも見るメトリクスに加えて、過去の障害のときの原因となったメトリクスも確認できるように、ダッシュボードをカスタマイズしていきましょう f:id:cybozuinsideout:20170621134840p:plain

無視しているアラートの共有

開発に注力するあまり運用やメンテナンスに力を避けていないプロダクトの場合、監視システムからのアラートを無視している可能性があります。 無視する正当な理由があることもあるので、無視しているアラートと理由、(わかっていれば)原因の共有を必ずしましょう。

新年度の切り替わり時などに発生する定期的な警告で無視しているアラートは必ず共有してください。 この引き継ぎをしないと新しい担当者が定期的な障害が発生した時に運用チームから問い合わせを受けても右往左往するしかありません。

稟議が要求されるタスクは作業手順書を作成する

運用チームが顧客情報を見せないなどのためににログ閲覧に制限を設けている場合があります。 ログを取得するために稟議を申請する必要があるときは、作業手順書を用意して後々の作業の負担を減らしましょう。

探求はつづく

プロジェクトの引き継ぎに関するベストプラクティスとアンチパターンを紹介しました。

未発掘のよいプラクティスがあると思うので、要探求です!「こんなのあるよ!」という方はコメントでぜひ教えてください!

プログラムが生み出してくれた価値に感謝することを常に忘れず、プログラムを愛でたいものですね。チャオ!

2016年 脆弱性報奨金制度を振り返って

$
0
0

こんにちは。Cy-PSIRT の山西です。

本エントリでは 2016 年に実施した脆弱性報奨金制度の結果、ご参加いただいた方向けのアンケートでいただいた質問への回答、2017年後半戦の取り組みについてまとめました。

ご報告くださった方、アンケートへ回答くださった方、ありがとうございました!

2016年の振り返り

定量情報

2016年のご報告数、報奨金のお支払金額は以下のようになりました。 f:id:cybozuinsideout:20170623135014p:plain

※ 数値の見方  外部からお寄せいただいた脆弱性情報は、受付 > 検証(再現確認)のプロセスを経て、脆弱性の認定手続きに進みます。  詳しくは過去の総括記事をご覧ください。

blog.cybozu.io

2016年報奨金額獲得ランキング

2016年にご報告いただいた脆弱性によって、獲得した報奨金額が最も多かったのは東内裕二(@yousukezan) 様でした。おめでとうございます。

f:id:cybozuinsideout:20170626092635p:plain

高額な脆弱性をご報告いただいた方ランキング

ご報告いただいた脆弱性が高額だった方ランキングも、全体のランキングに続き、東内裕二(@yousukezan) 様が 1 位でした。こちらもおめでとうございます。

f:id:cybozuinsideout:20170626092558p:plain

2016年のトレンド

前年以上に認定の可否を議論する機会が増えました。 2016年に社内で議論を重ねた報告については Cybozu Tech Conference 2016 で紹介した際の資料を公開しているので、よろしければこちらもご覧いただけると嬉しいです。

www.slideshare.net

それと同時に 2016年は、XSS の脆弱性がご報告数 1 位に返り咲きました。XSS単体では、前年より 10 件ほど多くご報告いただきました。

f:id:cybozuinsideout:20170623160617p:plain

新しい機能も追加されており、まだまだ「こんな脆弱性あるの?」と思ってしまうような脆弱性も眠っているかもしれません。 社内としてもそんな脆弱性達を撲滅するために新たな企画を考えておりますので、是非バグハンターの方々にもご協力賜りたいです。

アンケートでいただいた質問への回答

アンケートにご協力いただいた皆さま、貴重なフィードバックをありがとうございました。 いただいたご意見は今後の運営に生かすと共に、出来る限り要望にもお応えしていきたいと考えております。

報奨金のお支払い方法の検討

現在、報奨金のお支払いは口座振り込みでのみ行っております。口座振り込み以外で受け取りたいといった方もいらっしゃいましたので、その他のお渡し方法についても検討してまいります。

「脆弱性情報のご報告フォーム」で投稿したら自動返信をしてほしい

HPのご報告フォームに、自動返信の機能を早速設定いたしました。

認定までの期間を改善してほしい

現在は可能な限り 10 営業日以内に評価完了までご連絡できるように努めておりますが、報告が集中したり、報告いただいた内容が複雑だったりした場合には通常よりお時間をいただくケースもございます。ご了承ください。

修正の遅さを改善してほしい

申し訳ございません。セキュリティ品質の向上には日々努めておりますが、改修による影響範囲や脆弱性の与える深刻度によっては、改修が遅れる場合がございます。 また、クラウドサービスに比較してパッケージ製品はリリース間隔が長いため改修に時間がかかる傾向があります。 現在、そのような状況を解決するために開発プロセスの高速化に取り組んでおります。

修正までの期間が短い脆弱性の報奨金を上乗せしてほしい

CVSS の評価では、攻撃の容易度についても評価として考慮しておりますのでご要望にはお応え出来かねます。 また、前項で記載しておりますように、製品によってはリリースの間隔が異なり、改修期間で報奨金の上乗せをするのは難しい状況です。

2017年の取り組み

最大 5倍キャンペーン

最後のご案内になりましたが本日より報奨金の増額キャンペーンを実施いたします。

f:id:cybozuinsideout:20170623135407p:plain

詳細についてはキャンペーンページをご覧ください。

最大5倍キャンペーン

本制度の中では前例にない取り組みとなりますが、弊社の脆弱性に対する発見価値も高まってきており増額に踏み切りました。 対象製品は、Garoon、Office、メールワイズ がそれぞれ倍額。 kintone および、クラウド環境の共通管理画面(ログイン機能を含む)については、通常金額の 5 倍の額といたします。

報奨金獲得者のリアルタイムランキング

ご要望を多くいただいたため、リアルタイムランキングの実施を検討してまいります。 毎日の更新には対応できませんが、週 1 程度でランキングを公式 Twitter アカウント(@CybozuBugBounty)にてご案内いたします。 よろしければフォローをお願いします。最大 5倍キャンペーンで報奨金を獲得された方につきましても、こちらの公式アカウントにてつぶやいていく予定です。

バグハンター合宿

ご要望を多くいただいておりますので、今年の秋頃の開催を目指し検討を進めております。詳細は未定となっておりますが今しばらくお待ち下さい。

今後の活動について

今年の 1 月から Cy-PSIRT は、プロダクトセキュリティを担当するチームと社内のセキュリティ対策を行うチームを編成しました。よりセキュアに、そしてフットワーク軽く活動することを目標にしています。引き続きたくさんの脆弱性報告をお寄せいただけると幸いです。 報奨金制度に限らず「サイボウズにこんな企画してほしい」という要望がございましたら、 productsecurity@cybozu.co.jp までお気軽にご連絡ください。

よろしくお願いします。

脆弱性報奨金制度 | サイボウズ株式会社

スレッド名にデバッグ情報を埋め込むと激しく捗る件

$
0
0

こんにちは、アプリケーション基盤チームの青木(@a_o_k_i_n_g)です。

今回、Java のちょっとしたデバッグテクニックを紹介したいと思います。Java で運用中何かトラブルが発生した場合、スレッドダンプを取得することはしばしばあると思いますが、スレッドダンプだけだとちょっと情報が足りないことがあります。今回はスレッドダンプから得られる情報を増やして、素早く障害対応したりデバッグに役立てる方法を紹介します。

まずはじめに: スレッドダンプの取り方

基本ですが、改めてスレッドダンプの取得の仕方を紹介しておきます。スレッドダンプを取得する対象のプロセス ID を仮に 12345 として、下記のように jstackコマンドを実行すればスレッドダンプが取得できます(※Linux上で操作する想定)。

$ jstack 12345

対象のプロセス ID は ps aux | grep javaや、jps -lコマンドで調べましょう。

一つ注意点があります。jstackを実行するユーザーは Java プロセス実行ユーザーと同じユーザーでなければなりません。仮にログインユーザーが aoking で、対象プロセスの実行ユーザーが cybozu なら下記のようにしましょう。

$ sudo -u cybozu jstack 12345

さて jstack を発行するとこんなスレッドダンプが取得できます(一部抜粋)。

"Finalizer" #3 daemon prio=8 os_prio=0 tid=0x00007f31fc09c000 nid=0x57d4 in Object.wait() [0x00007f31ccd17000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x00000005cab10ff8> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
    - locked <0x00000005cab10ff8> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)
    at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)

"main" #1 prio=5 os_prio=0 tid=0x00007f31fc01a000 nid=0x57c4 runnable [0x00007f3204b90000]
   java.lang.Thread.State: RUNNABLE
    at java.util.regex.Pattern.<init>(Pattern.java:1351)
    at java.util.regex.Pattern.compile(Pattern.java:1028)
    at com.cybozu.common.Sample.main(Sample.java:8)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)

これはスレッドごとにスレッド名や優先度、スレッド ID、スタックトレース等を出力したものです。例えば例では mainスレッドと Finalizerスレッドがあり、mainスレッドでは java.util.regex.Patternクラスのインスタンス初期化をしている最中だということがわかります。

スレッド名に情報を埋め込もう

さて前述の例のスレッド名は mainFinalizerだったので一目瞭然でしたが、一般的なスレッド名は pool-472-thread-6392qtp278934944-22などで、実質意味を成さないものがよくあります。ここに任意の名前を埋め込んで、デバッグ効率を高めましょう。

早速例を見てみます。

long customerId = ...
String requestId = ...

Thread current = Thread.currentThread();
String originalName = current.getName();

String name = String.format("blob-add-%d-%s", customerId, requestId);
current.setName(name); // スレッド名をセットtry {
    addFile(...);
} finally {
    current.setName(originalName); // スレッド名を元に戻す
}

こちらは cybozu.com内で利用しているファイルサーバーの実装を元にした例です。このファイルサーバーに対してファイル追加を行うリクエストが来た時を想定しています。ここでは、ファイル追加処理であるという目印(blob-add の部分)と、顧客 ID、それからリクエスト ID というものをスレッド名に載せています。リクエスト ID とは cybozu.com へのアクセスごとに割り当てられる ID のことで、このリクエスト ID があればどのサーバーに何時にアクセスしたのかということがわかるようになっています。

この処理を入れておくと、スレッドダンプを出した際のスレッド名が blob-add-52153-1bd6bb9a88cc4adのようになり、スレッドダンプを眺める時に「ファイル追加処理が怪しい。顧客 ID 52153 のユーザーに影響が出ていそうだ、リクエスト ID を元に他のログを見よう」ということができるようになります。

これはあくまで例であり、アプリケーションによって必要な情報は大きく異なります。過去の障害調査の経緯などを参考にしてスレッド名に埋め込む情報を決めると良いでしょう。

処理が終わったらスレッド名を元の名前に戻しておくと良いです。理由はふたつほどあります。ひとつ目は、スレッドは処理が終わったらスレッドプール内で寝ているので、その寝ている時のスレッドと処理中のスレッドを見分けるため、という理由が一つ。もうひとつは、スレッドが再利用された時、スレッド名を適切な名前に設定していなかったらリクエストとスレッドの情報に乖離が生じることになってしまう、という理由です。

スレッドプールの名前を任意の名前にしよう

前章では Web アプリケーションをイメージしており、リクエストごとにスレッド名を指定する作りでした。しかしアプリケーションの種類によっては、スレッド個々についてではなくスレッドプール単位で情報が分かれば良い、というケースもあります。

Java でスレッドプールといえば ExecutorServiceが便利なので良く使われますが、こちらはデフォルトだと pool-7-thread-5のような味気ないスレッド名が使われます。ExecutorServiceを使う場合でもスレッド名を自由に設定することができるので、今回の例では新規にスレッドが生成される度にスレッドに番号を埋め込む方法を紹介します。

通常、ExecutorServiceの生成は Executors.newCachedThreadPool()あたりが良く使われます。このメソッドには java.util.concurrent.ThreadFactoryを渡すことができ、ThreadFactoryではスレッド生成時の処理を書けるので、そこで任意の名前を設定することができます。

コード例です。

publicclass CybozuExecutors {
    publicstatic ExecutorService newCachedThreadPool(String poolName) {
        // ここのスレッド名の %d にスレッド番号が自動的に割り当てられる
        ThreadFactory factory = new CybozuThreadFactory(poolName + "-thread-%d");
        return Executors.newCachedThreadPool(factory);
    }

    privatestaticclass CybozuThreadFactory implements ThreadFactory {
        privatefinal AtomicInteger counter = new AtomicInteger();
        privatefinal String threadNameFormat;

        private CybozuThreadFactory(String threadNameFormat) {
            this.threadNameFormat = threadNameFormat;
        }

        @Overridepublic Thread newThread(Runnable r) {
            // ここでスレッド名をフォーマットする
            String name = String.format(threadNameFormat, counter.incrementAndGet());
            returnnew Thread(null, r, name);
        }
    }
}

使う側ではこのようにして呼び出して ExecutorServiceを生成します。

ExecutorService executor = CybozuExecutors.newCachedThreadPool("mail-processor-" + customerId);

するとこの executorを使ったタスクのスレッド名は mail-processor-52153-thread-3mail-processor-52153-thread-27のようなスレッド名になり、顧客 ID 52153 のメール関連の処理を担当するスレッドということがスレッドダンプから一目瞭然になります。

注意点。CybozuThreadFactoryはあくまでサンプル用に書いたコードです。実際に使う場合は Guava の ThreadFactoryBuilder等を使うと安全でシンプルに ThreadFactoryを生成できるのでおすすめです。

最後に

スレッド名にデバッグ情報を埋め込むのは大変便利ですが、当たり前すぎるのかあまり紹介されないテクニックなので今回紹介させていただきました。適切な情報をスレッド名に指定しておくと原因や影響範囲が特定しやすくなり、結果的にユーザーへのサービス品質が高めることができると思います。

特にマルチスレッドなプログラムはデバッグに大変時間がかかることが多いです。スレッド名の改善だけで解決できるようになるわけではありませんが、解決困難な現象に立ち向かう時のひとつの手がかりとしては有用なので、ぜひ参考にしてみてください。

それでは、良いデバッグライフを!

大阪で「SRE」「生産性向上」「スクラム/アジャイル」を肴にミートアップ!

$
0
0

こんにちは。隙あらばコネクトしようと考えている風穴(かざあな、@windhole)です。

6月17日(土)に、サイボウズ大阪オフィスにて「Cybozu Meetup Osaka #2 SRE、生産性向上、スクラム/アジャイル」を開催しましたので、レポートします。

f:id:cybozuinsideout:20170713123730j:plain

サイボウズのミートアップ

2017年2月からスタートした「Cybozu Meetup」は、サイボウズのエンジニアとカジュアルに交流する場として企画、開催しているイベントシリーズです。会場はサイボウズのオフィスなので、社内の雰囲気や社員の様子を、実際に肌で感じて頂ける機会でもあります。

第1回は、東京と大阪をTV会議システムで接続して同時開催しましたが、運営上、やや難しい面があることが分かり、それ以降は別々に開催することになりました。その後も東京は月1回のペースで開催していますが、大阪は今回が2回目ということになります。

久しぶりの大阪開催ということで、東京の3回分のコンテンツ(SRE、生産性向上、スクラム/アジャイル)をまとめてお送りする「豪華版」(自称)として企画しました。

開催時間も、東京は毎回平日夜ですが、今回の大阪開催は、土曜日の午後として、3つのトークをゆっくり聞いていただく趣向に。

SRE

f:id:cybozuinsideout:20170713123939j:plain

運用本部長の山本 泰宇(@ymmt2005)は、サイボウズのSRE(Site Reliability Engineering)チームについて紹介。オフレコなトピックも交えつつ、話はアーキテクチャ刷新プロジェクト「Neco」にまで及びました。

生産性向上

f:id:cybozuinsideout:20170713124008j:plain

生産性向上チームの宮田 淳平(@miyajan)は、自身が2015年8月に立ち上げた同チームについて、具体的な例を交えて紹介。会場からは「生産性向上のための新しいツールを導入する際に、抵抗勢力が出てきたらどうしてますか?」といった、生々しい(?)質問が出ました。実はこれ、東京開催のときも同様の質問が出ていました。サイボウズの生産性向上チームは、各開発チームからの相談や要望を受けて活動しているので、今のところ、そういう課題は出ていないのでした。「人は、他の人から言われたことをやらされるのは楽しくないですよね。なので、当人たちがやりたいと思うところから改善していくのが良いのでは」(宮田談)。

スクラム/アジャイル

f:id:cybozuinsideout:20170713124026j:plain

自身が旗振り役となって、サイボウズの開発チームへのスクラム導入を進めてきた天野 祐介(@ama_ch)は、その経験を紹介しました。会場からは、改善スプリントについての悩みや、KPTのやり方、トレーニングへの取り組み方などについて質問が出ました。スクラムは、悩みが尽きないですね……。

交流タイム

トークセッションの後は、ドリンク片手におやつをつまみつつの交流タイム。今回は、3つの異なるテーマを詰め込んだため、テーマごとに参加者が分断されるかも……とも思ったのですが、蓋を開けてみると、複数のトピックに関心がある方がほとんどで、参加者同士でも大いに話が盛り上がっていました。

f:id:cybozuinsideout:20170713124050j:plain

次回は9月?

次の大阪開催は未定ですが、3カ月に1回は……ということで、9月に開催できたらと考えています。ご興味ある方は、connpassグループ「Cybozu Inside Out」をチェックして頂ければ。

また、「こんなテーマを聞いてみたい!」とか「今度は松山で開催してほしい!」といったご要望があれば検討いたしますので、遠慮なくお知らせください。

おまけ:
開催前夜は、チームワークを高めるべく「たこ焼き」に挑戦しました。 f:id:cybozuinsideout:20170710070117j:plain

ではまた。

RでDatadogのデータを取得するパッケージをCRANで公開しました

$
0
0

ドーモ、SREチームの湯谷(@yutannihilation)です。ニンジャスレイヤー7周年おめでとうございます。

Wantedlyの募集ページにも画面が映りこんでいますが、SREチームではDatadogも使っています。

Datadogはグラフ描画も高機能で便利ですが、やはり慣れ親しんだRでグラフが描きたい。誰しもそんな気持ちになることもありますよね。ということで、datadogrというパッケージをつくりました。

https://cran.r-project.org/package=datadogr

インストール

datadogrはCRANにリリースされているのでinstall.packages()でインストールできます。

install.packages("datadogr")

使い方

認証

datadogrパッケージを使うにはまず、DATADOG_API_KEYという環境変数にAPIキーを設定します。これは、.Renvironに書いておくか、k9_auth()でインタラクティブに設定するという方法があります。

library(datadogr)

k9_auth()

上のコードを実行するとポップアップが出てきます。ここにAPIキーを入力するとDATADOG_API_KEY環境変数に設定してくれます。

f:id:cybozuinsideout:20170725084905p:plain

ちなみに、datadogrパッケージの関数にはすべてk9_というプレフィックスがつきますが、K9というのはDoctor WhoというBBCのSFドラマに出てくる機械の犬です。「Datadog」という言葉から私はこれを連想しました。

実は、もともとパッケージ名もK9にしていたんですが、パッケージの審査で「分かりにくくね??」(意訳)というツッコミを受けたので無難なパッケージ名にフォールバックしました。うう…

メトリクス名の一覧を取得

k9_list_metrics()を使うと、メトリクス名の一覧を取得できます。デフォルトだと直近1時間に値のあるメトリクス名が返ってきます。例えば、IO関連のメトリクスは以下のようなものです。

library(tidyverse)

k9_list_metrics()%>%
  stringr::str_subset("^system.io")#> This API is rate-limited and you have 98 requests left (reset after 2555 seconds)#> #>  [1] "system.io.avg_q_sz"  "system.io.avg_rq_sz" "system.io.await"     #>  [4] "system.io.r_await"   "system.io.r_s"       "system.io.rkb_s"#>  [7] "system.io.rrqm_s"    "system.io.svctm"     "system.io.util"#> [10] "system.io.w_await"   "system.io.w_s"       "system.io.wkb_s"#> [13] "system.io.wrqm_s" 

メトリクスを取得

k9_get_metrics()を使うとメトリクスを取得できます。

Datadogからメトリクスを取り出すには独自のクエリの記法があります(参考:Graphing Primer using JSON)。基本的には、

メトリクス名{スコープ} by {グループ}

という形式になります。

メトリクス名は上で取得したsystem.io.r_sのようなものです。スコープは、メトリクスを絞り込むためのもので、role:dbのようなタグを指定します。グループはメトリクスをどのように分けるかを指定するもので、たとえばホストごとのメトリクスが見たい場合はhostを指定します。

例として、roleタグがdbかつgroupタグがtest1のホストのsystem.io.r_sを、各ホストのデバイス単位で見たい、という場合を考えてみます。クエリは以下のようになります。

system.io.r_s {role:db, group:test1} by {host, device}

これをk9_get_metrics()のクエリ引数に指定すると、欲しいメトリクスが取得できます。デフォルトだと直近1日分のメトリクスが取得できます。

d <- k9_get_metrics(
  query ="system.io.r_s {role:db, group:test1} by {host, device}")

結果はデータフレーム形式になっています。タイムスタンプと値、それにスコープやグループに指定した属性値が入っています。

glimpse(d)
Observations:26,588
Variables:11$ timestamp    <dttm>2017-07-2322:30:00,2017-07-2322:35:00,2017-07-2322:40:00,2017-07-2322:45:00,2017-07-23 ...
$ value        <dbl>0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000, ...
$ metric       <chr>"system.io.r_s","system.io.r_s","system.io.r_s","system.io.r_s","system.io.r_s","system.io....$ display_name <chr> "system.io.r_s", "system.io.r_s", "system.io.r_s", "system.io.r_s", "system.io.r_s", "system.io....
$ query_index  <int>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, ...
$ interval     <int>300,300,300,300,300,300,300,300,300,300,300,300,300,300,300,300,300,300,300,3...
$ device       <chr>"sdb","sdb","sdb","sdb","sdb","sdb","sdb","sdb","sdb","sdb","sdb","sdb","sdb","sdb"...
$ group        <chr>"test1","test1","test1","test1","test1","test1","test1","test1","test1","test1","test1...$ host         <chr> "db-34", "db-34", "db-34", "db-34", "db-34", "db-34", "db-34", "db-34", "db-34", "db-34", "db-34...
$ role         <chr>"db","db","db","db","db","db","db","db","db","db","db","db","db","db","db","db", ...
$ expression   <chr>"system.io.r_s{device:sdb,group:test1,host:db-34,role:db}","system.io.r_s{device:sdb,group:test...

このクエリを文字列として組み立てるのは面倒なので、k9_get_metrics()にはquery引数の代わりにmetricscopeby引数を指定することもできます。以下のコードは上と同じリクエストを送ります。

k9_get_metrics(
  metric ="system.io.r_s",
  scope =list(role ="db", group ="test1"),
  by = c("host","device"))

他にも、fromto引数でメトリクス取得の期間を変えたり、.split_request引数でリクエストを日ごとに分割するかどうかを選べたりします。詳しくはドキュメント(?k9_get_metrics)をご参照ください。

グラフを描く

このデータを使って、最近はやりのjoyplot*1を描いてみましょう。ggjoyパッケージを使います。

library(ggjoy)# ホスト名を並べ替え
x <- d %>%
  mutate(host = factor(host, levels = naturalsort::naturalsort(unique(.$host))))

ggplot(x, aes(value, host))+
  geom_joy(fill ="tomato", colour ="white", alpha =0.8)+
  facet_wrap(~ device)+
  scale_x_sqrt(limits = c(NA,100))+
  theme_minimal()+
  labs(title ="system.io.r_sの分布",
       subtitle ="role:db, group:test1")

f:id:cybozuinsideout:20170725084937p:plain

ちなみに、scale_x_log10()(対数スケール)ではなくscale_x_sqrt()になっているのは、メトリクスにゼロが多くてlogだとエラーになるからです。 ゼロが多いのは当然で、よく使われるデータが正しくメモリに載っていれば読み取りのIOは発生しません。 逆に言うと、メトリクスが横長に這いつくばっているホストがいくつかいますが、これは読み取りIOが発生しているのでチューニングの余地があるという兆候です。

Datadogも便利なんですけど、こんな感じで多数のホストのグラフをひたすら並べていく、みたいなときはやっぱりRがやりやすいですね。

最後に

何かあれば、GitHubレポジトリのIssuesTwitterでお知らせいただけると助かります。

SREチームではDatadogをバリバリ使い倒せる人、私ならRのグラフにも勝てる!という猛者を募集しています。募集要項はこちらです。

*1:Joy Divisionのアルバム「Unknown Pleasures」のジャケットに似ていることから名付けられたグラフ。確率密度曲線を所狭しと並べていく。

Hardening 1010 Cash Flow に参加しました

$
0
0

こんにちは。東京品質保証部 Cy-PSIRT の長友です。主に弊社製品の脆弱性の調査・検証をしています。
今回は、2017年6月23日から24日にかけて沖縄県宜野湾市で開催された、Hardening 1010 Cash Flowに事業支援本部の石渡と私で参加しましたので、報告します。
Hardening Project

Hardening Project とは

Hardening Projectとは、セキュリティの競技の一つです。
チーム対抗で、脆弱性のあるECサイトの堅牢化技術を総合的に競い合います。セキュリティや運用に関する技術だけでなく、ビジネスを継続するためのスキルも問われます。
弊社もスポンサーとして協賛しています。

参加のきっかけ

私は学生時代から CTF (Capture The Flag)をやっていました。CTF 自体、非常に面白い競技なのですが、ほかにもセキュリティに関する面白い競技はないものか、と思っていたところ、Hardening Project の存在を知り、興味を持ちました。
まだまだ経験の浅いエンジニアなので、うまくいくかどうか自信はありませんでしたが、ひとまず「当たって砕けろ」の精神で参加申し込みをしました。(CTF だって、最初から自信をもって参加できていたわけではありませんから)
選考があるということで、参加できるかどうか不安でしたが、なんとか参加の権利を得ました。

参加決定後

石渡と私は、偶然にもサイボウズ社員が 2 人、同じチーム (Team #5 WannaEnjoy) として競技に参加することになりました。世間を騒がせた WannaCry にも負けず、Hardening を Enjoy するぞ! という願いを込めてこんなチーム名になりました。
まずはお互いの自己紹介をしたり、リーダーを決めたりした後、それぞれがどのようなスキルを持っているかの確認をしました。すると、それぞれ持つスキルが分散しており、バランスの良いチームだということが分かりました。ほっとしたことをよく覚えています。 その後、スキルマップに沿って、サーバ全体の堅牢化を担当する「堅牢化チーム」、与えられたサーバの運用・監視を担当する「運用チーム」、EC サイトの在庫管理や、チームの外の人や組織とのやり取りを担当する「ビジネス系チーム」に分かれ、それぞれに準備を進めて行きました。
私は運用チームだったので、当日の運用で必要になりそうなスクリプトを書いたり、触ったことのないミドルウェアを実際に触ったりして、当日に備えました。

Hardening 1010 Cash Flow 当日

1 日目は実際にビジネスとシステムの堅牢化作業を行う「Hardening Day」、2 日目は Hardening Day の振り返りを行う「Softening Day」が行われました。

Hardening Day 前日

前日の夕方に沖縄に到着しました。沖縄は梅雨明け直後でとても蒸し暑く、クーラーでちょうどいい温度になっている部屋に慣れ切った私はここで 3 日間過ごせるのだろうか、と若干の不安を覚えました。
ともあれ、Hardening Project に備えることにします。
ちょうど打ち合わせ会場に向かい始めたころ、運営から今回の競技で使う環境の情報や、競技ルールについての資料がメールで送られてきました。 資料をみて、私はたいへん驚き、焦りました。なぜなら、護るべきサーバがとても多いうえに、それぞれのサーバに入っているアプリケーションの大半が古かったり、脆弱性がたくさん報告されていたりするものばかりだったからです。さらに、インターネット回線を使ってアップデートすることができないと分かったので、これはどうしたものかなあ、と考え込んでしまいました。
打ち合わせ中は、沖縄のおいしい食事を味わいながら、資料を読み合わせしたり、議論をしたりしました。お刺身とそうめんチャンプルーがとてもおいしかったです。(今後参加される皆さん、次の日は本番なので、お酒は控えめにしましょうね。) ゴーヤチャンプルー打ち合わせが終わり、ホテルに戻った後 NVD や JVN iPedia でどのような脆弱性があるのか調べたり、利用されているミドルウェアの設定を調べたりしてから寝ました。(こちらも、次回以降参加される方はきちんと寝ましょう。睡眠不足はインシデントレスポンスの敵です。)

Hardening Day

戦いの日にふさわしい、爽やかな朝でした。
インシデントが起きた、まずいぞ! と訴えるという動画から競技は始まります。
最初は比較的穏やかだったので、パスワードを変えたり、与えられた環境にどのようなミドルウェアが入っているか調査したりしていました。しかし、いざインシデントが起きるとかなりうろたえました。頭が真っ白になって何をすればいいのか落ち着いて考えることができませんでした。
また、初期対応ばかりに追われ、根本的な対応を忘れてしまい、同じ脆弱性を突かれるというイベントが発生しました。
会場 Hardening Project にはマーケットプレイスと呼ばれる、セキュリティ系の製品やサービス、人的リソース等を調達できる仕組みが存在します。今振り返ってみると、その仕組みをうまく使いこなすのが重要だと思いました。今回 WannaEnjoy では 仮想環境上にあるすべての Windows 端末にセキュリティ対策ソフトを導入することを先に決めていました。そのおかげで、早い段階で Windows 環境に仕込まれたマルウェアを検知し、隔離することに成功しました。
マルウェアが隔離されて一安心、さすがマーケットプレイスの製品だ、と思って胸をなでおろしていたら、近隣のチームから「ランサムウェアだ!」という声が上がって、ぞっとしました。もし後回しにしていたら……と思うと、今でもぞっとします。
また、今回 Windows 環境に導入したソフトウェアをご提供いただいた会社の方から、導入のアドバイスをいただいたり、運用中のサービスに見つかった脆弱性のご連絡を頂戴しました。頂いたご指摘の中には、冷静に見ていれば気づけそうなものもあったので、第三者の目線はとても大切と痛感しました。Softening Day のプレゼンでもお伝えしましたが、本当に感謝が尽きません。

そんなこんなで、とにかく大慌てしていたら、いつの間にか10時間過ぎていました。人間の感覚というものは不思議なものです。

腹が減っては戦ができぬ、ということで、昼食においしいハンバーガーをいただきました。また、おやつの時間にはおいしいコーヒーとお菓子をいただきました。どれもとてもおいしかったのですが、対応で焦りすぎてじっくり味わう余裕がありませんでした。今度沖縄に行くことがあれば、もう一度食べたいです。 昼食のハンバーガー

Softening Day

Softening Dayでは、チームごとの振り返りの発表、Hardening Project で利用する環境の作成や当日の攻撃などを担当したチーム (kuromame6) からの解説などがありました。苦しめられていた脆弱性が単純なもので、落ち着いて考えればわかったかもしれない、と気付いたときの悔しさはすごかったです。
そして、なんと WannaEnjoy のチーム発表を担当することになりました。資料が完成したのが当日の朝でしたので、朝慌てて出来上がった資料を確認したり、発表原稿を作ろうとしてあきらめたりしていました。Hardening Day は終わったはずなのに冷や汗が止まりませんでした。
当日の発表はこちらの動画からご覧いただけます。
その後の結果発表で、株式会社ラック様よりスポンサー賞をいただきました。チームのバランスをご評価いただきました。本当にありがとうございました。なお、表彰式の様子はこちらからご覧いただけます。

今回の会場は海のすぐそばでした。せっかく沖縄に来たので沖縄らしいことをしたくなり、Softening Day のお昼休憩を使って少しだけ海に遊びに行きました。とてもきれいな海でした。潮風がとても気持ちよかったです。 沖縄の海

今後 Hardening Project に参加するみなさんへ

たくさん反省したいことはありますが、今後参加される皆さんにお伝えしておきたい、私の過ちをここに記しておきます。

慌てない、焦らない

慌ててはいけません。
慌てると、普段から使っているはずの簡単なコマンドの使い方が分からなくなりますし、机の上の物は落としますし、お手洗いに向かっている間にこけそうになりますし、本当に何もいいことがありません。(すべて本当に起きたことです……)
何か大きなことをする前は深呼吸して、落ち着いて行動しましょう。「本番環境を触るのだから当たり前では?」と思うかもしれませんが、その「当たり前」ができなくなるのが Hardening Project の恐ろしい(面白い?)ところです。

サーバの構成を把握するのはとても重要

たくさんのサーバの運用を任されます。たくさんあるので、たまに監視や設定が漏れます。そうやって対応が漏れたサーバでインシデントが起こります。
ですから、サーバの構成はきちんと把握しておきましょう。そして、きちんとすべてのサーバ(せめて、死守しなければならないサーバだけでも)をまんべんなく保守・監視しましょう。可能であれば、サーバの監視ツールや、構成管理ツールを導入すると、人間の手でやるより抜け漏れが少なくなるのでよいかもしれません。

「ほうれんそう」はとても重要

社会人の基本としてよく教えられる「報告」「連絡」「相談」は、Hardening Project 競技中も非常に大切です。たとえば、インシデントが起きたらチームに報告したり、ちょっとした設定を変えた後にはその旨を連絡したり、ちょっと悩んだらすぐ誰かに相談したり。これらはすべて普段の業務では「当たり前」と思われることですが、様々なイベントが同時多発的に起きる競技中はうっかり忘れてしまいがちです。そして、うっかり忘れていた「ほうれんそう」事項が原因で障害が起きる可能性が十分にあります。ですから、競技中は普段以上に「ほうれんそう」を大事にしていきましょう。
また、チーム全体で「ほうれんそう」がしやすい雰囲気のチームを作るように心がけるとよいでしょう。具体的には、どんなことでも相談しやすい雰囲気のチームを目指すとよいと思います。

非エンジニアメンバーの有効活用

チームメンバーの石渡からのメッセージも掲載します。エンジニアではないけれど Hardening に興味がある皆さん、必見です。

おまけで非エンジニアメンバーからのつぶやきです。
初期設定をやっている時間帯など、何もできない(と思って止まってしまう)時間帯が結構あったのですが、もっとできることがあったはずなので、非エンジニアメンバーがいるチームは、事前資料を入手したときに非エンジニアメンバーにやってもらいたい作業の洗い出しをできるだけ具体的にしておくと良いと思います。
例えば、webサイトをユーザー視点で定期的に見ていくとか、全てのメールを確認する(ための環境構築?)をして、とにかく返信するとか、初期から何も考えずに広告購入をするとか、そのメンバーのスキル等に合わせて当日の環境で対応してもらえそうなもの(でやっておくとエンジニアメンバーが助かるもの)を事前に洗い出して、とにかく動いてもらえるようにする、ということをしておくと、非エンジニアメンバーがいることがプラスに働くと思います。
また、技術系以外のところ(特に法務的なところ)は、思い切った行動(経営者への意見メールなど、運営サイドの予想を超えるもの)が評価されたりするようなので、非エンジニアで参加された方は、広い意味での「会社の堅牢化」のために必要なものは、思いついたら積極的に行動してみるのが良いと思います。

まとめ

Hardening Project の会場はまさに「精神と時の部屋」でした。10 時間でECサービスを Hardening することで、堅牢化の技術や心構えを一気に叩きこまれました。また、これからさらに技術を深めていくために、自分に足りないことを知ることもできました。それに、初対面の人といかにうまくやるか、考えるきっかけにもなりました。
Hardening は、コンピュータセキュリティインシデントにかかわる可能性のあるすべての人に薦めたい競技です。精神的にも肉体的にもきついことは間違いないですが、参加する前と参加した後では物の見え方が変わるかもしれません。私は変わりました。
最後になりましたが、Hardening Project 実行委員会の皆様、このような素敵な競技を開催してくださり、本当にありがとうございました。


x86/x64における小数から整数への丸め処理命令の変遷

$
0
0

こんにちは、サイボウズ・ラボの光成です。

今回は小数を整数に丸める処理に関して、x86/x64における命令がどのように変わってきたかを紹介します。

C++における小数から整数への変換ルール

まずC++における浮動小数点数型(float, double)を整数型(int, int64_tなど)に丸めるルールをおさらいしましょう。 floating-integral conversionsによるとその変換では小数点部分を取り除きます。 つまり1.5, 2.3, -2.9をintにキャストするとそれぞれ1, 2, -2になります。

なお整数型に入りきらないときの挙動は未定義です。

4種類の丸め規則

x86の浮動小数点数を扱うFPUは丸め処理のモードを4種類持ちます。 これはIEEE標準754の丸めモードの規則に従ったものです。

  • 最近接丸め(round to nearest(even) : RN)
  • 切り捨て(round down toward -∞ : RD)
  • 切り上げ(round up toward +∞ : RU)
  • 0への丸め(round toward zero(truncate) : RZ)

f:id:cybozuinsideout:20170814151516p:plain

それぞれの処理を図にしてみました。矢印で示される区間内の値が矢印の先の整数に丸められます。黒丸●はその点を含み、白丸○は含まないことを意味します。

切り捨ては負の無限大方向に切り捨てる、切り上げは正の無限大方向に切り上げます。 それぞれfloor()関数、ceil()関数に相当します。 0への丸めは0に向かう方向に切り捨てます。doubleからintにキャストするときのルールはこれに相当します。

最近接丸めは若干馴染みが無いかもしれません。 通常よく使われる四捨五入では1.5, 2.5, 3.5は全て2, 3, 4と切り上げます。 しかし、この方法だと多数の値を処理したときに全体として正の方向に大きくなる可能性があります。 そこで端数が0.5のときは偶数に向かう方向に処理します。つまり0.5は0に、1.5は2に、2.5は2になります。 こうすると多数のランダムな値に対しては切り上げと切り下げが均等になります。

丸めモードの中に四捨五入はありません。 これはxが0以上なら0.5を足し、xが負なら0.5を引いて0へ丸めればよいからです。

コードとしては

double round(double x)
{
    double c = (x >= 0) ? 0.5 : -0.5;
    return (double)(int)(x + c);
}

で実現できます。

昔のx86における整数型への変換方法

FPUの丸めモードは、通常最近接丸めに設定されています。 そうするとdoubleをintにキャストするにはモードを変更しなくてはなりません。 もしかしたらプログラム実行中にどこかでモードが変更されているかもしれないので、

  1. 現在の丸めモードを取得して保持する
  2. 丸めモードをRZに変更する
  3. fist命令でdouble→intキャストを行う
  4. 丸めモードを1.で取得したモードに戻す

という処理が必要になります。 FPUのモードを変更するのはなかなかコストが大きく、多数の小数を整数に変換する際にはそこがボトルネックになることもありました。 この状況はベクトル演算命令が追加されたSSE, SSE2でも変わりませんでした(cvtsd2si ~2004年)。

0への丸め命令の追加

そこでIntelはSSE3で0への丸め専用命令(fisttp, cvttsd2siなど)を追加します(2004年)。 これはFPU/SSEの制御レジスタに関わらず常に0への丸めを行う命令です。 そのためdoubleからintへのキャストを丸めモードを変更せずに実現可能となり、処理性能が向上しました。

切り捨て、切り上げ対応命令の追加

intへのキャストは高速に処理できるようになっていましたが、floor()やceil()関数の実装では従来のintへのキャスト同様、丸めモードを変更するか、あるいは符号を考慮しつつcvttsd2siをうまく使う必要がありました。 そこで丸めモードを自由に設定できるroundsdなどの命令がSSE4.1で追加されました(2007年)。

roundsd  xmm1, xmm2/mem, imm8
vroundsd xmm1, xmm2, xmm3/mem, imm8

vroundsdはAVXで追加された命令です(2011年)。 imm8で丸めモードを指定できます。

たとえば前述のround関数は次のように実装できます。 浮動小数点数の符号は最上位ビットにあるので条件分岐を使わずに実装しています。

// xmm0にxが入っているとする
vandpd   xmm1, xmm0, ptr [const1] // xの符号ビットを取り出す
vorpd    xmm1, xmm1, ptr [const2] // xmm1 = (x >= 0) ? 0.5 : -0.5
vaddsd   xmm0, xmm0, xmm1         // xmm0 += xmm1
vroundsd xmm0, xmm0, 3            // truncate

const1: // 最上位ビットが符号ビット
  dd 0x00000000
  dd 0x80000000
  dd 0, 0
const2: // double(0.5)のビットパターン
  dd 0x00000000
  dd 0x3fe00000
  dd 0, 0

ただfloorやceilは整数が欲しいときに使うことが多いのにroundsd命令は結果が浮動小数点数型なので, 更にもう一度cvtsd2si命令を使って整数レジスタに変換しなければなりません。冗長な感じがします。

AVX-512命令

2016年IntelはAVX-512対応CPUを発表しました。 従来の256ビットSIMD命令だったAVX-2を2倍に拡張することで512ビットSIMD命令が使えるようになりました。 同時にほとんどの演算命令に個別に丸めモードを指定できるようになっています。

従来のvcvtsd2siも拡張されています。したがってこれ1命令でdoubleからintへの切り上げ、切り捨て、0への丸めが可能になりました。

アセンブリ言語では

vcvtsd2si eax, xmm0, {rn-sae}

のように指定します。", {rn-sae}“のカンマや丸括弧が気持ち悪い(というかパースしにくい)ですがこのように指定します。saeはSuppress All Exceptionsの略で小数演算例外を抑制します。

対応するintrinsic命令は _mm_cvt_roundsd_i64(__m128d, int r)です。

ただ手元で実験した限り、NASM 2.14rc0でアセンブルすると{rn-sae}を無視したコード生成をするようです(バグ? 報告してみました)。 intrinsic関数についてはVisual Studio 2017は非対応で、gcc-7.1やclang-4でコンパイルエラーになりました(もしかしたら私の使い方が悪いのかもしれません→2017/8/16 最後の段に加筆)。

拙作のXbyakはAVX-512に対応しておりたとえばvcvtsd2si(eax, xmm0 | T_rn_sae);と記述できます(サンプルコード round.cpp)。 AVX-512対応CPUを持っていない人でもIntel Software Development Emulatorを使えば正しく動いていることを確認できます。

sde -- round.exe

まとめ

x86/x64における浮動小数点数から整数への丸め方法について従来の方法から(2017年における)最新のプロセッサ向けの方法について紹介しました。 地味な下回りの命令ではありますが、今後対応したツールも増えてくるでしょう。

intrinsic関数での使い方

_mm_cvt_roundsd_i64(__m128d, int r)のrに指定する丸めモードはRN, RD, RU, RZに対応する0~3の整数ではなく、それと8(SAE)とのorをとる必要がありました。_mm_round_pdなら0~3を指定できるので私はそれと同じだと思い込んでいました。

int x = _mm_cvt_roundsd_i64(m1, 0); // error: incorrect rounding operandint y = _mm_cvt_roundsd_i64(m2, 0 | 8); // ok

0, 1, 2, 3, 8はヘッダでそれぞれ

#define _MM_FROUND_TO_NEAREST_INT 0#define _MM_FROUND_TO_NEG_INF     1#define _MM_FROUND_TO_POS_INF     2#define _MM_FROUND_TO_ZERO        3#define _MM_FROUND_NO_EXC         8

と定義されているのでこれらのマクロを利用してもよいでしょう。

デザイングループのお仕事、アクセシビリティへの取り組み──Cybozu Meetup #5 レポート

$
0
0

こんにちは、コネクト支援チームの風穴(かざあな)です。

6月20日に開催した「Cybozu Meetup #5 デザイン/アクセシビリティ」についてレポートします。

f:id:cybozuinsideout:20170812213426j:plain

Cybozu Meetupとは?

「Cybozu Meetup」も、早いもので、今回で5回目(東京開催として)となりました。

「Cybozu Meetup」は、サイボウズのエンジニアとカジュアルに交流する場として企画、開催しているシリーズです。会場はサイボウズのオフィスなので、社内の雰囲気や社員の様子を、実際に肌で感じて頂ける機会でもあります。

東京オフィスは毎月1回、大阪オフィスは3カ月に1回のペースで開催しています。毎回テーマを決めていて、これまでは、以下のようなラインアップで開催してきました。

そんな時代がサイボウズにもありました

第5回のテーマは、「デザイン/アクセシビリティ」ということで、まずは、サイボウズのデザイングループの活動について。

「デザイングループって、アイコンとかボタンとか作る部署でしょ」と思われていた時代が、サイボウズにもありました(笑)。そこから脱却し、「上流」から関わって活動することで、デザイングループの存在感が日々、高まってきています。

f:id:cybozuinsideout:20170812213523j:plain

f:id:cybozuinsideout:20170812213550j:plain

続いて、これも近年、社内で急速に動きが広まってきたアクセシビリティについて。

アクセシビリティの考え方をコツコツと社内で広め、遂には、正式に会社の活動として取り組むまでに持っていった小林が、サイボウズにおけるアクセシビリティ対応について紹介しました。

f:id:cybozuinsideout:20170812213629j:plain

質問&交流タイム

発表の後の質問タイムでは、「デザインプロトタイピングのスコープと周期は?」「アクセシビリティをやろうと思ってから実際に製品に反映されるまで、どれぐらいかかった?」「アクセシビリティに取り組むなら、どのタイミングでやるべき?」といった質問が出て、それぞれの議論もかなり盛り上がりました。

今回は、デザイン、アクセシビリティというテーマに直接関係している参加者が多かったせいか、その後の交流タイムは、いつも以上に突っ込んだ話で盛り上がりました。

f:id:cybozuinsideout:20170812213657j:plain

f:id:cybozuinsideout:20170812213809j:plain

最後は、恒例の集合写真!

f:id:cybozuinsideout:20170814151012j:plain

今後も、東京オフィスでは、毎月開催を予定しています。ご興味ある方は、connpassグループ「Cybozu Inside Out」をフォローして、情報をチェック頂ければ。

「サイボウズのこんな話を聞いてみたい!」というご要望も、随時、受け付けています。お気軽にお寄せください。

ではまた。

Migrating Garoon codebase to PHP 7

$
0
0

(※注 冒頭のみ日本語訳を行いました。本編はベトナムメンバーによる英語の記事になります。)
Xin chào! Cybozu Vietnam で Garoon を開発している Huy Nguyen, Vien Tran, Long Huynh, Dieu Ho, Tai Vu, Anh Nguyen です。ベトナムメンバー初のCybozu Inside Outの投稿です。Garoon で PHP 7 への移行をした経験を記事にしました。

One year ago, Garoon developement team started to migrate the codebase of Cybozu Garoon to PHP 7. Garoon is a product with large codebase, formerly written in PHP 4 and then later migrated to PHP 5. The migration really was a challenge to the team, but it was worth doing because PHP 7 brought a host of improvements. One of the benefits is performance improvements. Benchmark of Garoon using PHP 7 showed a 33 percent of speed improvement compared to PHP 5.6.

And also, active support of PHP 5.6 ended on 19 Jan 2017 according to php.net. Source: http://php.net/supported-versions.php

In this post, I will share things that the Garoon development team met and show you the way we migrated the codebase to PHP 7.

Tools to check incompatible changes

When we upgraded our code from PHP 5 to PHP 7, we had to check our codebase for all the “backward incompatible changes” to make sure our codebase could be successfully interpreted in PHP 7. There are some tools that help you scan your code through and point you out which code needs to be fixed in order to be able to run in PHP 7, among which are Phan and Lint.

Phan

Phan is a static analyzer for PHP. It’s licensed under the MIT License.

Prepare the environment

You have to prepare a CentOS machine, with PHP 7 installed. Then install composer running the code below:

curl \-sS https://getcomposer.org/installer \| php \-\- \--install-dir=/usr/local/bin \--filename=composer

Install Phan and the php-ast extension

First, clone the source code of php-ast:

git clone https://github.com/nikic/php-ast.git

Next, build the php-ast extension and then add it to php. Run each line of the code below in turn:

cd php-ast
phpize
./configure
make install
echo 'extension=ast.so' > /etc/php.ini

Then, install Phan, and run through the code below:

git clone https://github.com/etsy/phan.git
cd phan
composer install
./test
ln \-s /phan/phan /usr/local/bin/phan

Run Phan to check backward incompatible changes

We created a bash file (e.g., testPhan.sh) with the content like the following:

COMMAND="phan \--backward-compatibility-checks \--ignore-undeclared \--quick"
find /repo/source \-type f \-regex '.*\.\(php\)' \-print0 \| xargs \-0 \-n1 \-P 1 \-I % bash \-c "$COMMAND % "

You can change the path to the soure code by changing “/repo/source”. Then run:

sh testPhan.sh

Lint

Lint is a command line option provided by PHP, which is used to check PHP syntax.

On the above CentOS machine, we ran the following command to check our PHP source code with Lint:

find . -name "*.php" -print0 | xargs -0 -n1 -P8 php -l

E_STRICT notices severity changes

E_STRICT notices severity was changed in the PHP 7, and all of the E_STRICT notices were reclassified to other levels.

Situation New level/behaviour
Indexing by a resource E_NOTICE
Abstract static methods Notice removed, triggers no error
“Redefining” a constructor Notice removed, triggers no error
Signature mismatch during inheritance E_WARNING
Same (compatible) property in two used traits Notice removed, triggers no error
Accessing static property non-statically E_NOTICE
Only variables should be assigned by reference E_NOTICE
Only variables should be passed by reference E_NOTICE
Calling non-static methods statically E_DEPRECATED

Some of these changes affected our source code.

Signature mismatch during inheritance

The “Signature mismatch during inheritance” notice usually occurs in the following cases: The first case is a case where the number of the parameters of a function/method is different during inheritance. For example:

<?phpclass Foo{function method($a){}}class Bar extends Foo{function method(){}}

The above example outputs:

Warning: Declaration of Bar::method() should be compatible with Foo::method($a) in /in/YoDHq on line 11

You can click here to run this example and see the output.

The second is a case where the type of a parameter of a function/method is different during inheritance. For example:

<?phpclass Foo{function method($a){}}class Bar extends Foo{function method(array$a){}}

The above example outputs:

Warning: Declaration of Bar::method(array $a) should be compatible with Foo::method($a) in /in/fSIbS on line 11

You can click here to run this example and see the output.

We used Phan to check our code and fixed the problems that it reported as PhanSignatureMismatch and PhanSignatureMismatchInternal.

How to fix such issues depends on the logic that we modified in the base class or subclass.

Only variables should be assigned by reference

Example:

<?phperror_reporting(E_ALL);
function foo(){return'string';
}$temp=& foo();

The above example will output:

Notice: Only variables should be assigned by reference in /in/vXUIZ on line 6

You can click here to run the example and see the output.

In the above example, the ‘&’ operator causes an E_NOTICE saying “Only variables should be assigned by reference”. In case your code is compiled in a PHP 7 environment, an error will be detected, and so you must fix it by removing ‘&’ as follows:

<?phperror_reporting(E_ALL);
function foo(){return'string';
}$temp= foo();

However, since in our code ‘&’ was used in so many places and it would take us so much time to fix them all, I would like to introduce a tool which runs on CentOS to solve this problem. First of all, in order to write E_NOTICE messages to a php_error.log, you can do the following steps:

1. Add the following script to the code of your web application and then run it:

file_put_contents('/tmp/php_error.log', implode(',', [$errno, $[errstr], $errfile, $errline]) . PHP_EOL, FILE_APPEND);

2. The “php_error.log” will look like the following:

12 2048,Only variables should be assigned by reference,/var/www/project/code/xxx1.php,12
12 2048,Only variables should be assigned by reference,/var/www/project/code/xxx2.php,121
12 2048,Only variables should be assigned by reference,/var/www/project/code/xxx3.php,26
5 2048,Only variables should be assigned by reference,/var/www/project/code/xxx.php,194

The tool will run the following steps:

  1. Find the latest folder created with the prefix “ system-private-* ” under tmp.
  2. Grep the string “assigned by reference” in the php_error.log file, which exists inside tmp, and then output the file name and the line number to a temporary result.
  3. Find “=&”, “= &” and “= & ” and replace them with “=” following the result from the step 2.
#!/bin/bash

systemd_private_name=$(ls -t1F /tmp/ | grep systemd-private-* | head -n1)
php_error_path="/tmp/${systemd_private_name}tmp/php_error.log"

if [ ! -f $php_error_path ]; then
    echo "File is not found"
    exit;
fi


grep "assigned by reference"  $php_error_path  | sort | uniq -c | while IFS=',' read -ra line ; do
    sed -ri ${line[3]}'s/(\$.+)(\s+=\s*&\s*)(.+())/\1 = \3/g'  ${line[2]}
done

Only variables should be passed by reference

In PHP 7, using a function argument could return an error when the function argument was passed by reference. This issue can occur if you use a function of a PHP framework or a method you added.

To fix this issue we declared a variable to store the value of a function, which had been directly passed at a position called. What follows is an example:

Example: Strict Standards will be thrown out if you put exploded array in array_pop:

<?php$fruit=array_pop(explode(",", "Orange,Apple,strawberry"));
   echo$fruit;

Fixed code:

<?php$fruits=explode(",", "Orange,Apple,strawberry");
   $fruit=array_pop($fruits);
   echo$fruit;

Note that in this example you must assign a variable to the function explode and then pass the reference to the variable to array_pop to avoid a Strict Standard warning.

The methods in PHP framework

Example:

<?php$file_name="abc.txt";
   $file_extension=end(explode('.', $file_name));

The above example will output:

Notice: Only variables should be passed by reference in /in/Cv65t on line 3

You can click here to run the example and see the output.

Fixed code:

<?php$tmp=explode('.', $file_name);
   $file_extension=end($tmp);

We used Phan to check our code and fixed the problems which were reported as PhanTypeNonVarPassByRef. However, Phan only retrieved methods in the PHP framework: as for the methods we added, Phan could not detect them as PhanTypeNonVarPassByRef. The example below is to explain this point.

The method you added

Example:

<?phpfunction getArray(){return[1, 2, 3];
}function squareArray(array&$a){foreach($aas&$v){$v**=2;
    }}// Generates a warning in PHP 7.
squareArray((getArray()));

The above example will output:

Notice: Only variables should be passed by reference in in /in/HYONN on line 14

You can click here to run the example and see the output.

To detect a method you define in your project, you can search for it with regular expression using an editor (e.g, notepad++).

function.*\&\s+\$.*\)$

The above example will output:

E:\yourproject\comment_util.php (3 hits)
    Line 30:     function getFollowByUser( & $user, & $article )
    Line 61:     function _setNameRowSet( & $rowset, $inverse = FALSE )
    Line 119:     function _row2object( & $row )

After you list your reference methods from the search result, you must manually modify function calls.

Calling non-static methods statically

Static calls to methods that are not declared static are deprecated in PHP 7 and may be removed in the future.

We have an example:

<?phpclass foo {function bar(){echo'I am not static!';
    }}

foo::bar();

The above example will output:

Deprecated: Non-static method foo::bar() should not be called statically in - on line 8
I am not static!

We used Phan to check our code and fixed the problems that were reported as PhanStaticCallToNonStatic. The easiest way to fix such a problem is change all non-static functions to static functions.

PHP 4 constructor

PHP 4 constructors are methods that have the same name as the class they are defined in.

PHP 7 will emit E_DEPRECATED whenever a PHP 4 constructor is defined. When the method name matches the class name, the class is not in a namespace, and a PHP 5 constructor (__construct) is not present then an E_DEPRECATED will be emitted.

Example:

<?phpclass Filter {function Filter(){}}new Filter();

Output:

Deprecated: Methods with the same name as their class will not be constructors in a future version of PHP; Filter has a deprecated constructor in /in/IDpi7 on line 3

You can click here to run the above example and see the output.

You should use PHP 5 constructor like the below

<?phpclass Filter {function__construct(){}}new Filter();

If your project is large, manually fixing the constructors will take a lot of time. There’s a useful tool called PHP-CS-Fixer that can help you automatically fix them. The PHP-CS-Fixer tool helped us fix over 500 files in our Garoon project.

I will show you how to use the tool to fix PHP 4 constructors. The below code runs with PHP-CS-Fixer 2.2.1.

1. First we need to create a configuration for PHP-CS-Fixer

.php_cs
<?php$source_dir='c:\repo\projectX\source';
$finder= PhpCsFixer\Finder::create()->in($source_dir)->files()->name('*.csp')->name('*.php')
;

return PhpCsFixer\Config::create()->setRiskyAllowed(true)->setRules(array('no_php4_constructor'=>true))->setFinder($finder)
;

Note: Our Garoon project uses “.csp” as the file extension of PHP source files, which is why we add “.csp” to the configuration of PHP-CS-Fixer.

2. Run PHP-CS-Fixer

php php-cs-fixer.phar fix --config=.php_cs --verbose

For details about this tool, see: https://github.com/FriendsOfPHP/PHP-CS-Fixer

Internal functions Changes

There are some internal functions that were changed in PHP 7, and the substr() function is one of them.

For example:

<?php$foo=substr("foo",3);
if($foo!==FALSE){echo"PHP 7\n";
    echogettype($foo); //string}else{echo"PHP 5\n";
    echogettype($foo); //boolean}

The type of the variable $foo in the above example will be a boolean in PHP 5 and a string in PHP 7.

You can click here to run the above example and see the output.

To fix this issue, we checked the length of a string using the strlen function.

<?php$foo=substr("foo",3);
if(strlen($foo)==0){echo"Run on both PHP 5 and PHP 7\n";
    echogettype($foo); //boolean on PHP 5 and string on PHP 7}

You can click here to run the above example and see the output.

Conclusion

In the Garoon project, performance was improved and the codebase became more readable after the migration from PHP 5.6 to PHP 7: for example, the performance of the instance of Garoon we are using in Cybozu Inc. was shown to have been improved by 33 percent. We separated the migration into multiple parts and carried them out one by one. This way helped us cover possible issues while the migration was done in a short period of time.

Java Security Manager でセキュアなサービスを構築しよう

$
0
0

こんにちは、アプリケーション基盤チームの青木(@a_o_k_i_n_g)です。

今回は Java アプリケーションをセキュアに運用する仕組みである Java Security Manager について紹介しようと思います。この仕組みは Linux の強制アクセス制御機構(SELinux や AppArmor) の Java 版に相当するもので、プログラムの挙動を制限することができます。弊社が提供するクラウドサービス cybozu.comでも有効化されています。

セキュアなサービスを提供する上では良い仕組みだと思うのですが、検索したところ Java Security Manager に関する記事があまり多くなかったため、我々が得た知見をここに記します。

Java Security Manager とは

Java Security Manager (以下 JSM) とは、Java コードを安全に実行する仕組みの一つです。Java コード上で危険な操作を行う際は、事前に権限を許可しておかないかぎり実行に失敗し、例外をスローするというものです。危険な操作とは、例えばファイルの読み書きやネットワークへの接続、外部コマンドの実行、それからクラスローダーの取得やシステムプロパティの読み書きなどを指します。

初期状態では JSM は無効になっており、Java コードはどんな処理でも行えます。自由ではありますが、一方でこれは危険な状態でもあります。サードパーティのライブラリが勝手にファイルを読み書きしてしまったり、またはリモートコード実行という脆弱性が見つかった場合どんな操作でもされたりということが起こりえます。JSM で適切なポリシーを構築すればこれらの被害を抑えることが出来るでしょう。

ポリシーの作り方

許可する権限をまとめたものをポリシーと呼びます。JSM を有効に機能させられるかどうかはこのポリシーを正しく構築できるかどうかにかかってるといっても過言ではありません。

どのような処理がどのような権限の許可を必要とするのか、こちらの仕様書に一覧があるのでわかりやすいです。
Java Development Kit (JDK)でのアクセス権

既存のアプリケーションでどのような権限を要求されているかについて知りたい時は、まず最初に全権限を許可するポリシーファイルを作ります。

grant {
  permission java.security.AllPermission;
};

上記を all.policy のようなファイル名で保存し、対象の Java プログラムの起動オプションに -Djava.security.manager -Djava.security.policy=all.policy -Djava.security.debug=accessを指定して実行すると、下記のようなログが標準エラー出力に大量に書き出されます。これらのログは権限が必要になった時点でログに出力されるので、アプリケーションのすべての権限を集めたい場合は全機能を触る必要があります。こうして得たログを元にポリシーを構築しましょう。

access: access allowed ("java.lang.reflect.ReflectPermission" "suppressAccessChecks")
access: access allowed ("java.util.PropertyPermission" "java.security.egd" "read")
access: access allowed ("java.security.SecurityPermission" "getProperty.securerandom.source")
access: access allowed ("java.io.FilePermission" "/dev/random" "read")

ポリシーの記述方法

ポリシーを記述する方法はファイルに記述する方式と Java コードで記述する方式のふたつがあります。ファイルに記述する方式は公式ドキュメントでも解説されていますが、後述する性能問題やシンボリックリンクに関する問題があり、あまりお勧めしません。よってここではファイルに記述する方式の解説は省略し Java コードで記述する方式について解説します。

ポリシーをファイルに記述する方式に比べて、Java コードで記述する利点はいくつかあります。

  • パフォーマンスチューニングする余地がある
  • 複雑な権限評価を実装できる
  • ログ出力等も自由に可能

最小の記述で動かす例を示します。まず、下記のように java.lang.SecurityManagerjava.security.Policyを継承したクラスをそれぞれ作ります。SecurityManagerを継承したほうは現在は空ですが後述する性能問題でオーバーライドするのでここで定義しておきます。

publicclass CybozuSecurityManager extends SecurityManager {
}

publicclass CybozuPolicy extends Policy {
    privatefinal PermissionCollection permissions;

    public CybozuPolicy(PermissionCollection permissions) {
        this.permissions = permissions;
    }

    @Overridepublicboolean implies(ProtectionDomain domain, Permission permission) {
        return permissions.implies(permission); // 権限評価部分
    }
}

実際に権限評価を行う部分は CybozuPolicy#impliesメソッドです。今回のコード例では domainオブジェクトを無視していますが、domainオブジェクトを利用すればライブラリごとに評価する権限を切り替えるようなことができます。

上記のクラスを用いて、アプリケーションが起動した直後の処理に下記のようなコードを入れて JSM を有効化します。許可する権限は FilePermissionクラス等、Permissionクラスの子クラスのインスタンスで表現します。それらを先ほど作った CybozuPolicyクラスに渡し、Policy.setPolicy(Policy policy)で指定すれば権限が反映されます。

publicstaticvoid main(String[] args) throws Exception {
    // ここで許可する権限を記述。
    Permissions permissions = new Permissions();
    permissions.add(new FilePermission("/tmp/-", "read,write"));  // /tmp/下のファイルを読み書きを許可
    permissions.add(new ReflectPermission("suppressAccessChecks")); // リフレクションを許可
    permissions.add(new PropertyPermission("line.separator", "read")); // line.separator プロパティを読み込みを許可
    permissions.add(new RuntimePermission("getenv.PATH")); // 環境変数 PATH の読み込みを許可

    Policy.setPolicy(new CybozuPolicy(permissions)); // ポリシーの反映
    System.setSecurityManager(new CybozuSecurityManager()); // SecurityManager をセット(JSM 有効化)...
}

以上がほぼ最小の Java コードによる JSM を有効化する方法です。上記例で JSM を有効化した場合、例えば /proc下のファイルを読む、というようなことはできません。リモートコード実行の脆弱性があったとして、System.setSecurityManager(new EvilSecurityManager());のようなコードが実行されてしまうのではないか?という懸念があるかと思いますが、一度セキュリティマネージャーを設定した後再設定するには専用の権限を許可する必要があり、通常は行えません。

今後 SecurityManager を実装する方は、分散検索サーバーで有名な Elasticsearch のコードが参考になるかも知れません。

性能について

JSM を有効にする場合、既存の処理に加えてコードの各所で権限チェックが行われるので性能劣化を引き起こします。弊社のとある Web アプリケーションでは、特に性能について考慮せずナイーブにポリシーを構築した場合、応答時間が 3 倍程度まで伸びてしまいました。

これを改善するため、評価される権限のうちの一部頻繁に評価される権限について短絡評価を行うことにしました。短絡評価を行うには先ほどの CybozuSecurityManagerクラスで checkPermission(Permission perm)メソッドをオーバーライドし、その中にロジックを記述します。

コード例を示します。こちらはファイルを読み書きする際の権限が要求された際に /tmp/ から始まるパスなら実行を許可するという例です。

publicclass CybozuSecurityManager extends SecurityManager {

    @Overridepublicvoid checkPermission(Permission perm) {
        String name = perm.getName();
        String actions = perm.getActions();

        // ここで短絡評価を行い、実行可能な操作なら super.checkPermission(perm) を呼び出す前に return するif (perm instanceof FilePermission) {
            if (name.startsWith("/tmp/")) {
                return;
            }
        }

        ...super.checkPermission(perm);
    }
}

主に遅くなるのは SecurityManager#checkPermissionの処理のようでした。上記のような短絡評価を複数取り入れた結果、性能劣化は 3% 程度に抑えられました。潤沢なリソースがある本番環境ではほぼユーザーエクスペリエンスに影響がない範疇に収められたかと思います。ただし、公式ドキュメントでも指摘されているように、SecurityManagerクラスをサブクラス化する際は権限の評価漏れ等が起きないよう最新の注意を払ってください。

JSM をうまく扱うポイント

シンボリックリンクについて

ファイルやディレクトリを読み書きする権限を与えても、そのパスがシンボリックリンクだと正常に許可されないケースがあります。

具体的には、プログラム実行中にシンボリックリンクの指し先が変わるケースです。例えばシンボリックリンクのあるファイル /path/to/symlinkへの読み込みを許可するアプリケーションがあるとします。そのシンボリックリンクの指し先がアプリケーション実行中に変わると、同じ /path/to/symlinkの読み込みをしているにも関わらず権限は許可されません(内部でパス解決のキャッシュが効いているのか、指し先が変わっても最大 30 秒程度は許可されます)。

この現象は前述した短絡評価と同じようなコードを挿入することで解決できます。

外部コマンドの実行について

アプリケーション内から外部コマンドを実行する系がある場合、そのコマンドのパスは絶対パスで記述しましょう。というのも、JSM の実装の都合上、絶対パスでないコマンドを実行する時は 全ファイルの実行権限を許可する必要があるからです。

コマンド実行時に呼び出される java.lang.SecurityManagerの一部を転載します(整形済)。

publicvoid checkExec(String cmd) {
    File f = new File(cmd);
    if (f.isAbsolute()) {
        checkPermission(new FilePermission(cmd, SecurityConstants.FILE_EXECUTE_ACTION));
    } else {
        checkPermission(new FilePermission("<<ALL FILES>>", SecurityConstants.FILE_EXECUTE_ACTION));
    }
}

ここからわかるように絶対パスでない場合は常に <<ALL FILES>>、すなわち全ファイルの実行権限を要求されます。checkExecメソッドをオーバーライドして回避する方法もありますが、あまりハックらしきことはせず郷に従うほうが得策ではないかと思います。

ForkJoinPool について

通常、JSM を有効にするとどのスレッドでも同じポリシーが適用されるのですが、デフォルトの ForkJoinPoolで生成されたスレッドは例外です。

SecurityManagerが存在し、ファクトリが指定されていない場合、デフォルト・プールではファクトリが提供する有効なPermissionsを持たないスレッドが使用されます。 https://docs.oracle.com/javase/jp/8/docs/api/java/util/concurrent/ForkJoinPool.html

ForkJoinPoolのスレッドを使う時とは、ForkJoinPool.commonPool()を用いてタスクを処理したり、Stream API で parallelStream()を用いて並列にリスト処理を行う時などです。

これを解決するには下記のように自前で ForkJoinWorkerThreadFactoryForkJoinWorkerThreadを定義する必要があります。

publicclass CybozuForkJoinThreadFactory implements ForkJoinWorkerThreadFactory {
    @Overridepublic ForkJoinWorkerThread newThread(ForkJoinPool pool) {
        returnnew CybozuWorkerThread(pool);
    }
}

publicclass CybozuWorkerThread extends ForkJoinWorkerThread {
    protected CybozuWorkerThread(ForkJoinPool pool) {
        super(pool);
    }
}

上記クラスを定義した上でシステムプロパティで ThreadFactory を指定すると、意図したとおりのポリシーが用いられるようになります。

System.setProperty("java.util.concurrent.ForkJoinPool.common.threadFactory",
                      "com.cybozu.common.concurrent.CybozuForkJoinThreadFactory");

終わりに

JSM を用いるとアプリケーションの意図しない挙動を防ぐことができるので、よりセキュアにアプリケーションを運用することができます。万が一リモートコード実行のような脆弱性が見つかっても、 JSM が有効な範疇でコードが実行されるなら被害を最小限に留めることが出来るかも知れません。

とは言え、JSM を有効にしたからといって安心安全というわけでは決してありません。人間が作るものなので完全なポリシーを作ることなどきっと不可能でしょう。そうでなくとも、サーバーサイドで JSM を有効にしたとしても、 例えばエスケープ漏れによる SQL Injection や XSS などの脆弱性を防げるようになるわけではありません。JSM は数ある脅威のうちのほんのごく一部を防げるだけに過ぎず、過信してはならないことを肝に命じた上で JSM を扱いましょう。

参考

Javaセキュリティ・アーキテクチャ

サイボウズ・ラボユース合宿2017開催

$
0
0

こんにちはサイボウズ・ラボの光成です。

先日(8/23~8/25)、サイボウズ・ラボユース合宿をしたのでその紹介をします。

合宿の概要

サイボウズ・ラボユースは学生のソフトウェア開発を支援する制度で、詳細は「第6期サイボウズ・ラボユース成果発表会」開催などをご参考ください。

合宿の目的は、ラボユース生同士、交流を深めてもらうことです。 今年度はリモート参加の学生も多く、なかなか他の学生と交流しにくいだろうという背景があり、久しぶりの開催となりました。

もちろん集中的に開発し、様々な疑問をまとめて聞ける場を提供するのも大きな目的の一つです。

合宿の参加者は現役のラボユース生が4名、研究生が1名、ラボユースOBが4名、ラボからは7名で、 会場は神奈川県三浦海岸のマホロバ・マインズ三浦でした。

男性参加者は3~4人一組で泊まるのですが、部屋が約100平方メートル3LDKとかなりの広さで快適でした。

f:id:cybozuinsideout:20170828154516j:plain

女性参加者は一人だったため、その広さを少々もてあましていたそうです。 今後は女性の参加者が増えるとよいですね。

初日

遠方参加者がいたため11時過ぎの自己紹介でスタートです。 最近はSECCONなどの影響もあり、CTFをやっている学生も多く、開発テーマをそれ関係にしている人もいました。 みなさん黙々と開発していました。 私はすぐ寝ましたが夜遅くまで開発していた人もいたようです。

二日目

朝からずっと開発です。気分転換に自由に使えるラウンジに移動して開発してる人もちらほらでてきました。 バイナリ(機械語)が好きな人が多かったので私は息抜きネタにあなたの知らないnopたちのLTをしました。

それからC++を勉強中の希望者に対して『Effective C++』をベースにC++11, C++14で便利になった機能の紹介をする勉強会をしました。 こういうところでは時間を気にせず質問タイムを多く取れるのがよいですね。

f:id:cybozuinsideout:20170828144333j:plain

三日目

合宿での成果発表会です。

城倉さんは去年のラボユースのOBでその後未踏IT人材発掘・育成事業:2017年度採択プロジェクト概要に採択されました。 将来そのプロジェクトで動かす予定のネットワークパケットフィルタを開発しました。

f:id:cybozuinsideout:20170828182634j:plain

渡部さんは「拡張可能なインタプリタのための、構文解析のための、DSLの設計」という発表でした。 きちんとした理論を元に考察し、OCamlで実装されていて興味深いです。

f:id:cybozuinsideout:20170828182657j:plain

高品さんはTwitter上のソーシャルグラフのクローラを作って(twicrawler)、収集したデータから日本の機械学習界隈の中で影響力の大きい人たちを表示するデモを行いました。 結構それっぽい人たちが選ばれていて面白かったです。

f:id:cybozuinsideout:20170828183854j:plain

川田さんはCTF用のカーネルエクスプロイト問題を作ってみようと調査しました(資料)。

f:id:cybozuinsideout:20170828183824j:plain

dmsgのFreeing SMP …の項目に表示されていたアドレスは安全性のため新しいkernelでは表示されなくなってるそうです(mm/page_alloc: Remove kernel address exposure in free_reserved_area())。へえ。

黒岩さんはROPチェインの自動生成ツールを開発しています。

f:id:cybozuinsideout:20170828183814j:plain

ROPとはバッファオーバーフローなどを利用する攻撃の一つで実行属性のないスタック上で意図したコードを実行する手法です。 glibcなどに含まれるコード片を組み合わせてコードを構築するのですが、その部分を自動化しようというものです。

西田さんはネタアプリとしてC言語を補助してくれるslack上で動くbotを作りました。

f:id:cybozuinsideout:20170828182645j:plain

「putsの中身を"○○"にして」と発言するとソースコードが修正されます。 「インデントくらいしてよ」と発言するとソースコードをきれいにフォーマットしてくれる機能もあります。

ちなみにフォーマットツールにはClangFormatを使っているとのことで、「indentじゃないの?」と尋ねたところ「indentって何ですか」と言われてジェネレーションギャップを感じました。

赤間さん(OB)は、プラレールのレイアウトを設計するためのツールに必要な座標系の話でした(cf. プラレールで半加算器を設計した話)。

f:id:cybozuinsideout:20170828182639j:plain

平行移動と45度だけ回転する座標をうまく簡潔に表現できないか考えているそうです。

粟本さん(OB)はLinuxのuio(ユーザ空間でデバイスドライバを作る仕組み)の紹介とxHCI用ドライバの進捗状況を発表してくれました。

f:id:cybozuinsideout:20170828144413j:plain

緑川さん(OB)はとあるマイナーな公開鍵暗号に対する攻撃方法を考えていました。

まとめ

みなさん好き勝手にやっていて(ほめ言葉)すばらしい。 今後のすぐれた成果を期待します。 なお、サイボウズ・ラボユースは通年募集しております。

f:id:cybozuinsideout:20170828144420j:plain

遅いクエリと向き合ったり、ログ基盤を刷新したり──Cybozu Meetup #6レポート

$
0
0

まいど! コネクト支援チームの風穴(かざあな)です。

今回は、7月25日に開催した「Cybozu Meetup #6 大規模サービスを支える名脇役たち」についてレポートします。

f:id:cybozuinsideout:20170821122829j:plain

Cybozu Meetupとは?

「Cybozu Meetup」は、サイボウズのエンジニアとカジュアルに交流する場として企画している、ミートアップイベントです。会場はサイボウズのオフィス(今のところ東京と大阪)なので、社内の雰囲気や社員の様子を、実際に肌で感じて頂ける機会でもあります。

開催ペースは、東京オフィスは毎月1回、大阪オフィスは3カ月に1回となっています(今のところ)。これまでに、以下のようなテーマで計6回開催してきました。

アプリケーション基盤チーム

東京開催、第6回目のテーマは「大規模サービスを支える名脇役たち」。

「名脇役って何?」という声が聞こえてきそうですが(実際、社内でも、そういう声が……)、要するに、サイボウズが提供しているクラウドサービスやソフトウェアを支える基盤システムのことです。製品やサービスの「顔」として語られることはないけど、重要な役割を果たしている……という思いが、このタイトルに込められているのでした。

その「名脇役」を支えているのが、「アプリケーション基盤チーム」です。一般にミドルウェアとかフレームワークと呼ばれるもの等を守備範囲として活動しています。あるいは、ログ基盤、メッセージキュー、全文検索、ユーザ管理機能といった「サイボウズの複数製品で使うプログラムを作るチーム」(アプリケーション基盤チーム・赤井駿平)でもあります。

トークタイムでは、そのアプリケーション基盤チームから、以下の2名がそれぞれのテーマで発表しました。

f:id:cybozuinsideout:20170821122902j:plain

f:id:cybozuinsideout:20170821122936j:plain

質問&交流タイム

発表の後の質問タイムでは、「(ログ基盤システムで)Fluentdを採用しなかった理由は?」「ログは、どれぐらいの期間の分を残してますか?」「kintoneでは、MySQLのindexはどのようにしてますか?」など、いつになくガチな質疑応答となっていました。

特に、Fluentdを採用しなかった理由については、Fluentdガチ勢の皆さんからツッコミが。詳しくは、以下のまとめ(Togetter)をご覧ください。

Cybozu Meetup #6 サイボウズのサービスを支えるログ基盤(Togetter) https://togetter.com/li/1142720

その後は、立食形式で楽しい懇親会へ。

f:id:cybozuinsideout:20170821123001j:plainf:id:cybozuinsideout:20170821123042j:plain

今後も、東京オフィスでは、毎月開催を予定しています。ご興味ある方は、connpassグループ「Cybozu Inside Out」をフォローして、情報をチェック頂ければ。

「サイボウズのこんな話を聞いてみたい!」というご要望も、随時、受け付けています。お気軽にお寄せください。

f:id:cybozuinsideout:20170821123100j:plain

ではまた。

技術顧問に聞いてみた──小崎資広さん、武内覚さんインタビュー

$
0
0

こんにちは。コネクト支援チームの風穴(かざあな)です。

この度、あの小崎資広さん、武内覚さんに、サイボウズの技術顧問に就任していただくことになりました。

小崎さんは、日本を代表するLinuxカーネル開発者の一人です。また武内さんも、Linuxカーネル開発者として知る人ぞ知る存在で、最近では、AMD Ryzenプロセッサの問題を追究したことでも注目を集めました。

ということで、さっそくお二人にお話を伺ってきました。

サイボウズSREチームと、小崎さん、武内さんの集合写真
サイボウズSREチームのメンバーと(前列左から4人目が小崎資広さん、同5人目が武内覚さん)


──そもそも、このお話の経緯は?

小崎さん(以下、敬称略):山本さん(編注:山本泰宇、サイボウズ執行役員・運用本部長)から、「技術顧問になっていただけませんか?」とオファーをいただきまして。

──それまでは、山本とは知り合いでした?

小崎:以前、2、3回、お会いしたことがあり、お名前は認識してました。こちらはすっかり忘れていたのですが、山本さん、沼津の私のオフィスまで来てくれたことがあり、どうもその時打ち合わせで同席していたらしいというのが後から分かって。

武内さん(以下、敬称略):私もいました!

──いきなりでビックリしました?

小崎:そうですね。

武内:不思議な縁ですね。

小崎:それとは並行してサイボウズ社の内田さん(編注:内田公太、サイボウズ・SRE)からOpen Source SummitでWalB(※1)の発表をするので、その資料をレビューしてもらえないか、という相談をいただいていて、内田さんとは一緒に作業をしていました。

武内:その会話を小崎さんがTwitterでしているとき、私が巻き込みリプライをされて。

小崎:「何でこの人が@に入ってるんやろ?」と(笑)。今あらためて見直したら武内さんがWalBの話をしたところに星野さん(星野喬、サイボウズ・ラボ)と山本さんがJoinする形で会話をしてて、そこになにも考えずに返信してたんです。

武内:えー、ひどい話だ(笑)。でも僕は、風穴さんの書籍プロジェクトで内田さん、星野さんとは知り合いだったし、面白そうだからと議論の輪に入りました。

──お二人にたくさんレビューしていただいたおかげで、WalBの発表は大成功でした。ありがとうございました!

武内:そのWalBの発表が終わった頃に、山本さんから連絡があって、技術顧問としてやっていただけませんか、と。私は、春に会社を辞めたばかりで、しばらくは就職せずに、家に籠って自己鍛錬するつもりだったんです。そしたら、そんな私にピッタリの契約が提示されて。

──すごいタイミングですね!

武内:ホントに(笑)。なので、そういう形なら全然いいです、やります、と返事しました。

──その後、小崎さんも所属元とサイボウズの間での調整が終わり、サイボウズの技術顧問をやっていただけることになったわけですが、ちなみに、サイボウズにはどんな印象を持ってました?

小崎:僕は元々、風穴さんとか、サイボウズ・ラボの西尾さんとかと付き合いはありましたし、そういう印象でした。

──おー、そうなんですね。武内さんは?

武内:サイボウズの印象は2段階あって、最初は、サイボウズ・ラボの印象でした。セプキャン(編注:セキュリティ&プログラミングキャンプ、現在のセキュリティキャンプの前身)の講師をしていたので、そこで竹迫さん(元サイボウズ・ラボ)、川合さん(サイボウズ・ラボ)と知り合いました。なんかずいぶん元気な、というか、楽しそうに仕事している人がいるな、と(笑)。

小崎:わたしも同じ年にセプキャンに参加していたので、このあたりの方々とは面識がありました。

──ラボの印象だったんですね。

武内:次が、例の書籍プロジェクトで星野さん、光成さん(サイボウズ・ラボ)、内田さんと出会って、みんなゴリゴリの技術屋で、やっぱりすごく楽しそうだなと。しかも、すごく社内の風通しが良くて、なんて仕事がしやすそうなんだ、と。そういう印象です。あと最近では、働き方の話で、ずいぶん攻めたことをする会社だなと(笑)。

小崎:そうそう。働き方改革とかでもサイボウズがすごくバズってるなと。あの広告(※2)とかで。

──そうですね。ここ1年ぐらいは特にそうですね。

武内:他に例がないというか、いろんなことをされていて、すごいな、という印象はありましたね。

話題になったkintoneの広告ポスターの画像
話題になったkintoneの広告ポスター


お二人の「伝説」

──小崎さんって、いつ頃からすごい人になったんでしたっけ?

小崎:何をいきなり(笑)。

──カーネル読書会で、glibcのmallocについて発表したのがコミュニティデビュー?

小崎:ですね。それより前は、すごく昔に、RELAX(REgular LAnguage for XML)というスキーマ言語のJISテクニカルレポートに、Special Thanksとして名前が出たぐらいかな。なので、Linux系では、あれが最初。

──カーネル読書会で、mallocの発表をされたときは、まだLinuxカーネルはお仕事じゃなかったんですよね?

小崎:そうなんですよ。

──私も、そのときのカーネル読書会に参加していましたが、ホント衝撃的でしたね。

小崎:あの後、社内で仕事をしてると、何か知らんけど、代わる代わる社内の人がやって来て、柱の向こうから私を指差して帰っていくんですよ。ものすごい、感じ悪い(笑)。

武内:それは、感じ悪いですね〜(笑)。

小崎:オマエもやってたやないか!(笑)

武内:私も4人ぐらい連れて行きましたよ。あれが小崎さんだ、って。当時、「Linuxカーネルやglibcが専門じゃない部署の人が何でこんなにglibcのmallocに詳しいんだ?」って、社内で話題になって、見に行きました(笑)。それからが縁ですね。それまでは、同じ社内にいても、小崎さんの存在すら、僕らは認識してなかったですから。

──カーネル読書会の発表が、そんなことになってたとは。

武内:でも、あのときはまだ「普通のすごい人」という感じでしたよね。

小崎:それ、形容詞が矛盾してるような(笑)。

なお、もはや伝説となっている、カーネル読書会での小崎さんの発表「mallocの旅(glibc編)」は、以下で見ることができます。


──武内さんは、まずインターンで富士通に行ったんですよね。

武内:そうです。どうしてもLinuxカーネルがやりたいと思って探したら、富士通がインターンを募集していたので、そこでちょっと頑張ったら、そのままLinuxの開発をやってる部署に採用されて、12年かな、勤めました。

小崎:この人は、インターンの頃から伝説を持っていて。

武内:僕は、大学の学部が情報系じゃなかったので、何か印象を残さないとダメだなと思って、当時触ったことのなかったIA-64 Linux上でハードウェアデバッガを使ってファームウェアがOSに渡したテーブルを書き換えたり、色々やりましたね(笑)。

小崎:何学部でしたっけ?

武内:材料工学。

小崎:それでよくインターンの書類選考が通ったよね。

武内:そうそう(笑)。何か、いろいろ書いた気がします。無茶なことを。

──大きな会社だと、やりたいと言っても、なかなかその通りには配属されないことも多いですからね。

武内:いやぁ、奇跡ですよ。すごく良い巡り合わせでしたね。入社してからは、Linuxカーネルのプロセススケジューラの改善というのをやってました。さらに、社内のOS教育もやることになり、その流れで、セプキャンの講師に呼ばれて……。それが社外への認知の第一歩ですね。

──小崎さんも、大学は情報系じゃないんですよね?

小崎:物理屋さんです。大学を卒業したときが、ちょうど就職氷河期だったので、あまり選べずに家電メーカーの子会社に進みました。ちょうど家電にOSが入り始めた頃で、最初はまだITRONだったけど、その後、Linuxになって。

──スタートは組み込み系だったんですね。

小崎:そう。組み込みでソフトを書いていると、何でこう動くんだろうと、OSのカーネルのコードを読まないといけないことが多々あって……。さらに、周りにそれを説明する必要もあったので、カーネルやらglibcやらの資料を山ほど書いて、説明するということに慣れました。なので、その後エンタープライズに移ったら、そこでは激しく分業が進んでいて、みんな自分の専門以外は知らないということに、ものすごく驚きました。

武内:あるある(笑)。

小崎:結局、最初に就職したところで、たまたま、大きなプロジェクトに入って、大量のソースコードに触れたっていうのが転機になった気がしますね。家電って、ユーザがリモコンを操作して動かない、となったら「リモコンを押したけど動きませんでした」というバグチケットが切られるんですけど、その犯人捜しが困難を極めるわけですよ(笑)。するといつも貧乏くじを引く人がいて、横断的にコードレビューをして突き止めたりする必要があるわけ。そういうのを繰り返して、すごく大きいソフトウェアに対して、何とかしてコントローラブルにするっていうのが、だんだん得意になってきて、それが後々、だいぶ役に立ちましたね。

小崎資広さんの写真
小崎資広さん


技術顧問としての抱負

──今後、どうする、こんなふうにしたい、みたいなのはありますか? 個人的なことと、それから技術顧問としての2つの視点で。

武内:個人的なことで言うと、私、退社の寸前までBtrfsの開発をやっていました。それを、今でいうext4みたいに、あらゆるユーザが使うファイルシステムにしたいです。なので、またその開発に戻ったり、資料を書いて広めたりして、何とか流行らせたいなと。これはすごく良いものだと、自分では思っているので。

──Btrfs! 私も、個人的にBtrfsには期待してるので、ぜひ頑張ってください!

武内:技術顧問として何ができるかというと、何だろなぁ、やっぱり、アプリケーションより下のレイヤ、特にglibcとかカーネルとか、その辺の低レイヤのことをもっと知ってほしいかなと。当たり前のように話せるようになってほしいので、そのお手伝いができればと。

──なるほど。それもぜひ!

武内:あと、わたしは前職では障害が発生したら社会インフラが止まるし、すぐに原因究明をして対策を考えないといけないシステムを扱っていました。その経験を共有し、サイボウズのサービスをより良くしていくことに貢献できたらなと思ってます。

──ありがとうございます! では、小崎さんは?

小崎:なんか、美味しいところ全部取られちゃって言いにくいんですけど(笑)。私はLinuxカーネルのdevelopmentのほうにいたというのが、特色としてあると思ってます。ネットで検索できるLinux記事は、特にトラブルシューティングの記事が結構間違ってたりするんです。動作原理を知らないからそうなってしまうんですけど。ですからLinuxの設計や、なぜそう動作するのかといったところも含めて共有しつつ、一緒に最高のサービスを作っていきたいです。

──小崎さんご自身は、いま、技術的にはどの辺に興味あります? Linuxカーネルだとメモリ管理ですよね?

小崎:そうですね。私はメモリ管理周りが専門です。ただ、カーネルの中の活動をする前はHPC屋さんで、パフォーマンスチューニングをやってました。そのあたりはそれなりに知識があるので、そういうところもSREの領域に生かせると思っています。

働き方は変わった?

──ちなみに、生活というか、働き方みたいなものは、技術顧問就任で変化はありますか?

武内:僕は、しばらくは仕事をしないつもりだったので、適度に仕事が入るかな、というぐらいですね。どっちかというと、小崎さんのほうが変化はあるんじゃないですか?

小崎:忙しいは忙しいんですけどね。だいぶ配慮していただけているので、それで回せてますね。サイボウズさん以外だったら、こういうのは無理だったかもしれないですね。

──そういう面はあるんですね。

武内:私もそうですね。さっきも言いましたが、こっちの都合に会社のほうが合わせてくれるっていう……なんて会社だとビックリしましたよ(笑)。すごく助かりましたね。

武内覚さんの写真
武内覚さん


最後にひと言

──最後にひと言、お願いします。

武内:サイボウズのエンジニアの方々って、みんなすごい優秀なんですけど、「サイボウズがオープンソースソフトウェアに、こういうコントリビュートをしました」みたいなのが、外にはまだそれほど見えてきていないので、それは何とかしたいですね。サイボウズは、働き方はすごい、というのに加えて、こんなにすごいエンジニアがいるっていうのを、ラボの面々だけでなく、サイボウズ本社のほうからも、どんどん出ていくといいのかなと思ってます。

小崎:その辺は、我々もだいぶ、何と言うか、empowerするのは得意なので、ぜひやりたいですね。

武内:例えば、WalBをアップストリームに持っていくとか、その他の機能改善とか開発とか、何でもいいですけど、それをOSSに持っていくというときに、どうやればいいのかといった点は、我々はまさに得意技なので、外に出るお手伝いはできると思いますね。

小崎:我々、文化が違うところから来てるので、お互いに学びあっていけるといいな、と。それを通じて、ぜひとも新しい価値をお互いに作っていくことができたらなと思っています。よろしくお願いします!(了)

kintoneゲーストスペースの画面
お二人とのやり取りは、kintoneのゲストスペース(kintoneの利用ユーザー以外の人が、ゲストとして参加できるスペース)で行っています。


文責・写真:風穴 江


※1:「WalB」(ワルビー)は、サイボウズ・ラボの星野を中心に開発されている、Linux用のバックアップおよび非同期レプリケーションのためのシステムです。ブロックデバイス層でWrite-Ahead Logging(ログ先行書き込み)を行っているのが大きな特徴で、オープンソースソフトウェアとして公開されています。

WalB v1.0 リリース

※2:鉄道駅などで展開された、kintoneの広告。皮肉な「煽り」広告として、BuzzFeed(「ノー残業、楽勝!予算達成しなくていいならね」 サイボウズの煽り広告がよくぞ言ってくれた!──上司の皆さんは耳が痛いのでは)などでも話題に。


サイボウズサマーインターン2017 報告その1〜品質保証・セキュリティコース

$
0
0

こんにちは!品質保証部の中園です。

サイボウズでは今年もサマーインターンシップを開催しました! 昨年好評をいただいたので、今年はどーーーんとパワーアップして5コース用意しました。

  • Webサービス開発
  • モバイルアプリ開発 (New!)
  • UX/UIデザイナー
  • 品質保証/セキュリティ
  • Site Reliability Engineering (New!)

今回は、品質保証/セキュリティコースについて、第1回の内容をお伝えします。

f:id:cybozuinsideout:20170904112051j:plain

インターンの概要

第1回は08月21日~08月25日で開催しました。品質保証/セキュリティコースは2名の学生さんが参加してくれました。

本コースでは、サイボウズ製品の品質保証活動がどのようにして行われているか、品質がどのようなプロセスで確保されているのかを、実際の業務を体験しながら学んでいただきました。

5日間のスケジュールです。

f:id:cybozuinsideout:20170904110451j:plain

製品テスト、セキュリティ、不具合情報公開サイトの運営の業務をほぼ日替わりで体験してもらいました。

今年は品質保証部内で自主的に開催している勉強会に参加してもらったり、品質保証部の部長とざっくばらんにお話しする機会があったりと、かなり内容の濃いインターンシップになったのではないでしょうか。

製品テスト

製品テストでは、kintoneの『アプリのアイコンを変更できる機能』を題材に、テスト設計からテスト設計レビュー、テスト実施までの流れを体験してもらいました。

1日目はテスト設計をしてもらいました。

テスト設計では、kintoneのプログラマが作成した本物の機能仕様書を見ながら、テスト仕様書を作成します。

f:id:cybozuinsideout:20170904111018j:plain

機能仕様書を網羅したテスト仕様書を作成することを意識しながら、目標時間内に無事に完成させることができました。

2日目は、作成したテスト仕様書を学生同士で交換し、レビューを行いました。手順のミスや、抜けている観点を指摘します。

互いにテスト仕様書をレビューすることで、それぞれ新たな視点に気づいていた様子でした。

f:id:cybozuinsideout:20170904112327j:plain

学生同士のレビューが終わったら、答え合わせの時間を設けました。

メンターが作成したテスト仕様書を見せながら、テスト設計のやり方や、よく使っているテスト技法などを紹介しました。

そして、メンターが作成したテスト仕様書をもとに、テスト実施もしてもらいました。 (「手順が分かりやすい!」「スッキリしていて見やすい!」などの声をいただき、大変恐縮でした…!)

また、不具合を見つけて、報告するまでの流れを体験するために、kintoneのアドホックテストも実施しました。 いくつか不具合を報告していただき、kintoneの品質向上に貢献してくれました!

セキュリティテスト

サイボウズ製品のガルーンを対象として、セキュリティテストを体験してもらいました。

まずは、セキュリティテストの位置付けとセキュリティテストに必要な知識の講義を行いました。

セキュリティテストはテストプロセスのサブプロジェクトです。製品のテスト担当者からセキュリティテストを依頼されます。

f:id:cybozuinsideout:20170927144835p:plain

講義が終わり、テストに利用する Burp Suite の設定を行っていきます。通信の内容を確認することで、それぞれのリクエストでどのような情報が送られているのかが分かり、また、テスト時には通信の内容を改ざんすることで、脆弱性がないかを調べることができます。

次は、サイボウズで検証している脆弱性を紹介していきます。サイボウズは CWE 識別子を使って脆弱性を識別しています。採用している脆弱性は、クロスサイト・スクリプティング、SQL インジェクション、CSRF 等様々です。

以前のバージョンで発生しており、現在は改修された脆弱性を使ったハンズオンも行いました。

f:id:cybozuinsideout:20170928133510p:plain

これで検証に必要な知識を得ることが出来ました。準備万端です。

早速、テスト設計を行っていきます。製品テストと同様に機能仕様書を見ながら、ガルーンの新機能がどのようなものかを把握していきます。

機能仕様書と実際の環境を見比べながら、追加された画面でどのようなリクエストが発生するかを洗い出していきます。 インターン生はメンターからのアドバイスを受けながら、無事テスト仕様書を完成させることが出来ました。

テスト仕様書が出来たら、実際の検証作業を実施します。

どのような手順で確認すればよいか・脆弱性の場合どのような挙動になるか・脆弱性ではない場合どのような挙動になるかといった内容が記載されているページを確認しながら検証を進めていきます。

サイボウズでは、セッション・リクエスト・パラメーター単位でテスト項目が決まっています。

f:id:cybozuinsideout:20170927144926p:plain

それぞれの検証を一つずつ実施していきます。中にはパラメーターが多く、検証に時間がかかるリクエストもあります。

すでに検証済みのバージョンということもあり、残念ながら今回は脆弱性を見つけることはできませんでしたが、検証のやり甲斐や面白さを体感してくれたようでした。

不具合情報公開サイトの運営

サイボウズでは、製品を利用しているお客様や、サイボウズ製品を取り扱っているパートナー様に向けて、 製品の不具合/脆弱性/制限事項に関する情報を不具合情報公開サイトで公開しています。

昨年に続き、今回のインターンでも「不具合」と「脆弱性」の2種類の記事を、ガルーンを対象として作成してもらいました。

始めに、メンターから不具合情報公開サイトの運用や業務体験の内容について説明しました。

その後、インターン生に記事作成を次の流れで実施してもらいました。

  1. 社内の検出情報をもとに、現象(不具合または脆弱性)が発生する手順を把握する。
  2. 実際に製品を操作し、以下の項目を検証する。
    ・現象が発生するバージョン
    ・他の箇所でも同様の現象が起きないか
    ・検出情報以外の再現手順はないか
  3. 検証した結果をまとめ、公開する記事を作成する。

実際に作業を進めると、発生するバージョンの切り分け方や、読者が読みやすく検索しやすい記事に仕上げるにはどうしたらよいかなどで、悩んでいたようです。

そのときには、メンターのアドバイスを受けながら進めてもらいました。

f:id:cybozuinsideout:20170927142048j:plain

記事が仕上がったら、メンターとインターン生全員で記事を確認し、良かった点やもう少し工夫した方がよい点をメンターからフィードバックしました。

最後に、公開した情報がどのように活用されているかを紹介し、不具合情報公開サイトの公開目的を理解していただきました。

サイボウズの品質保証活動の一連の流れを感じながら作業していただけたようで、嬉しい限りでした!

青野社長とのランチ

インターン期間中、社長の青野とのランチの機会も設けました!

f:id:cybozuinsideout:20170928124242j:plain

サイボウズ創業のことから、働き方改革について、更には今後のビジョンについてまで、幅広い話を聞きました。 社長から直々に話を聞けたおかげで、サイボウズについてより深く知ることができた様子でした。

成果報告会の様子

最終日の成果報告会では、他のコースと合同で、サイボウズ社員向けにインターンの成果を発表します。

f:id:cybozuinsideout:20170904114244j:plain

成果報告会では、50人近くの社員が参加しました。他拠点へも、テレビ会議システムを使い中継されていました。 どのコースも社員が驚くような成果で、議論や意見交換も活発に行われました。

成果報告会を終えた後、打ち上げ兼懇親会を開催しました。

f:id:cybozuinsideout:20170904115219j:plain

サプライズでロールケーキタワーを用意していました!

f:id:cybozuinsideout:20170904115223j:plain

大変名残惜しかったですが、これにてインターンの全日程が終了しました。

インターン生の感想

最後に、インターン生の感想を紹介します。

  • 品質保証/セキュリティコースのインターンシップを通じて、品質保証とは製品がお客様からの期待に応えられるかどうかを判断できる最後の確認する場所であることを体感でき、製品がリリースされるうえで最も重要な品質保証の一連の流れを学ぶことができました。 業務内容だけでなく、メンターさんや人事の方、またインターン生みんな親切でいい人だったのでお話することも本当に楽しかったです!長いようで一瞬の楽しい5日間でした。サイボウズで働けたらとても楽しいと心の底から思います!楽しい5日間をありがとうございました。

  • 品質保証部の業務を幅広く体験できたので全体的に良い構成だと思いました。特に実際の自社製品を使ってリアルな体験をできるところが魅力的なところだと思います。自社製品を使って品質管理や脆弱性診断を行うことで、業務に対する感覚を掴むことができました。毎日の内容が濃くて、5日間があっという間でした!本当に充実した5日間でした。メンターの方々に業務のことだけではなく、これからやるべきことなどの相談にも乗っていただけたので本当に感謝です。

まとめ

今回も非常に優秀な学生さんたちに参加して頂き、メンターとしても良い刺激をもらいました。 5日間という短い期間でしたが、サイボウズの品質保証部のこと、サイボウズという会社のことを多く吸収していただけたようでした。 学生の皆さんの今後の活躍を期待しています!

お知らせ

サイボウズではPSIRTの学生アルバイトを募集しています。 セキュリティに興味がある方、ぜひチェックしてみてください。

サイボウズサマーインターン2017 報告その2〜UX/UIデザイナーコース

$
0
0

みなさんこんにちは、デザイングループの西藤です。

先日、Cybozu Summer Internship 2017が開催されました! 今回のサマーインターンのアシスタントをさせていただいた自分からデザイングループのインターンの様子をお届けしたいと思います!

f:id:cybozuinsideout:20171005135258j:plain

インターンの概要

サイボウズサマーインターンは毎年8月から9月にかけて3回開催されます。5日間を通して実際の業務の疑似体験をしてもらうことはもちろん、参加者と企業がお互いをより深く知ることを目的としています。

インターンでは業務体験以外のイベントも多く開催されています。例えば

  • 歓迎会、懇親会
  • 社員による勉強会
  • 社長とのランチ
  • メンター以外の気になる社員との面談
  • 社内LTイベントに参加 など

f:id:cybozuinsideout:20171005141800j:plain
青野社長と開発本部長とのランチ会の様子

では実際にデザイングループではどういうインターンシップを行ったのか紹介します。

課題について

今回の課題は「デザイングループのマネージャーの柴田さん(以降、柴田さん)がkintoneモバイルの通知処理から解放されるUX/UI」です。

f:id:cybozuinsideout:20171005173140j:plain

課題は「リサーチ」「プランニング」「プロトタイピング」のプロセスで行いました。この3つはデザイングループで大切にしていることで、その部分を体験してもらいました。 「リサーチ」「プランニング」はグループワーク、「プロトタイピング」は個人で作業、最終発表はグループで行ってもらいました。

f:id:cybozuinsideout:20171005142811p:plain

1. リサーチ

kintoneモバイルを触って、そこから自分たちで何をヒアリングしたら良いか考えてもらいました。ヒアリングする時のコツをリサーチャーから伝授してもらい、実際のターゲットである柴田さんにヒアリングを行いました。そこから今回の課題のペインと理想のゴールを考えてもらいました。

質問の仕方がわからずヒアリング中に沈黙してしまうこともありましたが、自分たちで何に困っているのか、どう困っているのかをしっかり聞き出してくれていました。 f:id:cybozuinsideout:20171005143513j:plain

2. プランニング

ぺインとゴールを考えた後は「アイデアの発散」→「アイデアシート作成」→「シナリオコンテ作成」という流れで制作を進めました。 それぞれの段階でメンターや柴田さんにフィードバックをもらいながら改善を重ねていきました。

自分に対するフィードバックだけでなく、他のインターン生に対するフィードバックも参考にしながら改善を考えてくれていたのでより良い案になったと思います。

f:id:cybozuinsideout:20171005143839j:plain
アイデアの発散中
f:id:cybozuinsideout:20171005143922j:plain
アイデアシートの発表
f:id:cybozuinsideout:20171006101126j:plain
実際のシナリオコンテ

3. プロトタイピング

プランニングで決めた案に対して「ペーパープロト作成」→「Sketchを使ったプロトタイプ」→「モーションの追加」という実際の業務と同じ流れで制作してもらいました。 慣れていないFlintoやSketchといった実際の現場で使うソフトにも積極的にチャレンジしてくれました。わからないところはメンターに個別に聞いたりアドバイスをもらいながら、試行錯誤して自分のアイデアの理想形を作っていきました。

インターン生同士で、デザイン案の意見交換を自主的にやっていて、インターン生同士のチームワークが芽生えていてとてもよかったです。

f:id:cybozuinsideout:20171006095707j:plain
プロトタイプ作成中
f:id:cybozuinsideout:20171005150013p:plain
柴田さんからのフィードバック
f:id:cybozuinsideout:20171005150404j:plain
インターン生同士で意見交換

成果発表

英語でスピーチしたり、イラストをふんだんに使ったり、ムービーを作ったりと個性を活かした発表をしてくれました。 また、何よりインターン生同士のチームワークが伝わる発表だったのがとてもよかったと思います。 会場からは、大きな歓声があがっていて最高の発表になったと思います。

f:id:cybozuinsideout:20171005145213j:plainf:id:cybozuinsideout:20171005144337j:plain

インターン生たちの感想

f:id:cybozuinsideout:20171005165843p:plain:w100:left最初2日間がWSでそのあと個人のワーク2日間という流れはすごくよかったです!特に最初の2日間のWSを3人のインターン生と一緒にできたことで、チームワークが生まれ、個人作業でのツッコミや、パワポの練習を誘い合って開催するなどの良い流れにつながっていたと思います!
f:id:cybozuinsideout:20171005165852p:plain:w100:leftオフィスや社内環境はすごく好きです。開放感あふれていてみなさん問題にチームで取り組んでいる感じ、そしてピリピリしておらず気持ちの面で繋がっているのが垣間見えました。本当にありがとうございました。
f:id:cybozuinsideout:20171005170011p:plain:w100:left今回のインターンでとても良かったと思う点は、社内の雰囲気を中から体験できたことです。提案的な内容とはいえ、短期間でも充実した体験をすることができました。また、メンターの方々や、人事の方々のフォローもとても手厚く、ストレスなく取り組むことができたのもとても良かったです。
f:id:cybozuinsideout:20171005170058p:plain:w100:left大学で学ぶデザインと仕事としてするデザインは質の部分で違うということや、受注デザイナーと自社製品デザイナーの働き方の違いなど日頃考えていたことに対する新しい考え方を得られました。
f:id:cybozuinsideout:20171005170117p:plain:w100:left会議室などではなく、実際にデザイナーやエンジニアが働いているオフィスで社員の方と同じように実践的な作業ができたことはとても良かったです。今回、初めて触れるソフトがありましたが、メンターの方が丁寧に教えてくださったので、とても勉強になりました。5日間、ありがとうございました!
f:id:cybozuinsideout:20171005170136p:plain:w100:leftこの夏のインターンに求めいていたこと全てができて、大満足です。新しいスキルも学べましたし、全日程を通してメンターさんも適切なフィードバックをくれて、自分の成長に直結しました。 コミュニケーションを取ることを大事にしていたので、正直な意見をきちんと受け入れて対応してくれたのが嬉しかったです。

まとめ

今回参加していただいた6名とも、実際にプロダクトにとりこんでみたいと思わせるレベルの案を、5日という期間でばっちり出せていてとてもよかったと思います。
またお互いの成果物がより良くなるよう力を合わせ、「チームワーク」で課題に取り組んでいる姿が素晴らしかったと思います。

今年も大成功に終わったサマーインターンですが、来年ももちろんやります! UX/UIデザインに興味のある学生のみなさん、ぜひ来年の夏にお会いしましょう!
インターンシップへの応募だけでなく、新卒採用、中途採用、複業採用への応募も絶賛お待ちしています! デザイングループの採用ページはこちらです!

https://cybozu.co.jp/company/job/recruitment/designgroup/

デザイングループのFacebookページ 「UX Cafe」

デザイングループの活動や、UXに関わる勉強会・ワークショップなど様々なイベントに関する情報を発信しています。

Safari 11 Intelligent Tracking Preventionについて

$
0
0

はじめまして、開発基盤部フロントエンドエキスパートチームの小林(@koba04)です。 チームメンバーがまだひとりなので、仲間を募集中です!

macOS High Sierra及びiOS11のSafariで導入されたIntelligent Tracking Preventionについて紹介します。

詳細は、下記のWebKitのブログに書かれていますが、Intelligent Tracking Preventionはクロスサイトトラッキングを制限することを目的とした機能です。

クロスサイトトラッキングとは

まず最初にクロスサイトトラッキングとは、複数サイト間でのユーザーの行動をトラッキングすることです。 クロスサイトトラッキングを行うには、トラッキングしたいサイトに、Cookieを設定した共通のリソースを埋め込みます。 これにより、トラッキングしたいサイトでのユーザーの行動を、共通のリソースによって設定されたCookieを通じて紐付けることができます。

また、この時に利用されるCookieを一般的にサードパーティCookieと呼びます。

これまでの挙動

Intelligent Tracking Preventionが導入されるまでは、SafariのCookieに対する設定は「訪問したWebサイトを許可」がデフォルトになっていました。 したがって、これまでもユーザーが一度も訪れていないサイトによるトラッキングはできませんでした。

ただし、リダイレクトなどを用いてユーザーが認識してないうちに訪問させることが可能でした。

Intelligent Tracking Prevention

macOS High Sierra及びiOS11のSafariでは、SafariのCookieに対する設定は「サイト越えトラッキングを防ぐ」がデフォルトになります。 この設定により、Intelligent Tracking Preventionが有効になります。

Intelligent Tracking Preventionは、ユーザーの行動データを収集し、それによってサイト毎にCookieを含むストレージデータの扱いを変更します。

データ収集

Intelligent Tracking Preventionは、リソースの読み込みだけでなく、タップ、クリック、テキスト入力のようなユーザーインタラクションのデータを収集します。 収集したこれらの情報は、サブドメインを含まないトップレベルのドメインごとに集計されます。 blog.cybozu.ioの場合は、cybozu.ioごとに集計されます。

その後収集したデータを元に機械学習を行い、クロスサイトトラッキングを行っている疑いがあるドメインを分類します。 今のところ、次の3つの要素が分類に対して強い影響を与えていることが明らかになっているようです。

  • 多数のユニークドメインに配置されているリソース
  • 多数のユニークドメインに配置されているフレーム
  • 多数のユニークドメインに対するリダイレクト

ただし、分類の詳細については明らかにされていません。

また、これらのデータ収集及び分類は、全てデバイス上で行われます。Appleには送信されません。

分類後

上記の機械学習による分類で、クロスサイトトラッキングを行っている疑いがあると判定されたドメインは、下記のように扱われます。 「分類されてから」や「最後に訪問してから」ではなく、「最後のユーザーインタラクションから」というのがポイントです。

最後のユーザーインタラクションから24時間以内

そのドメインのCookieを、サードパーティーCookieとして利用することが出来ます。 したがって、この段階ではクロスサイトトラッキングが可能です。

最後のユーザーインタラクションから24時間以上30日未満

Cookieなどのデータを、Cookieを発行したドメインとアクセス元のドメインの組み合わせごとに異なる保存領域に保存します。 このドメインは、サブドメインを含まないトップレベルのドメインとなります。 この状態になると、サブドメインを含む同じドメインの中ではサードパーティCookieを共有できますが、別ドメインとは保存領域が異なるためCookieを共有できません。 そのため、クロスサイトトラッキングはできなくなります。

最後のユーザーインタラクションから30日以上経過している

Cookieなどのデータは即時に削除されて、その後追加されるデータも削除されます。 したがって、Cookieやストレージが使えない状態となります。

影響

クロスサイトトラッキングを行っている疑いがあると分類される基準が不明なため、影響範囲を特定するのは難しいですが、下記のような影響が考えられます。

  • サードパーティのCookieに依存した計測が出来なくなる
    • ユーザーが実際に利用するようなサイトでも、クロスサイトトラッキングを行っている疑いがあるドメインと分類されてしまうと、最後のユーザーインタラクションから24時間経過した時点で、サードパーティCookieとして使えなくなります
    • したがって、Cookieに頼らずURLのクエリーとして値をドメイン間で受け渡しするなどの対策が必要となります
  • ログイン情報の共有が出来なくなる
    • 最後のユーザーインタラクションから24時間以上経過するとCookieの共有が出来なくなるため、例えばソーシャルサービスのボタンを別サイトに設置した場合、サービス自体にはすでにログイン済みにも関わらず、ボタンを利用する際に再度ログインが必要となる状況が発生します
  • ユーザーインタラクションのないサイトでCookieやストレージが利用出来なくなる
    • ユーザーインタラクションのないサイトでCookieやWebStorageなどを利用している場合、クロスサイトトラッキングを行っている疑いがあるドメインと分類されてしまうと、これらのデータを保存することが出来なくなります

質問してみた

冒頭で紹介したブログ記事に質問があったらTwitterで聞いてとあったので、いくつか質問してみました。

  • どのドメインがIntelligent Tracking Preventionで分類されたのかわからないけど何か知る方法はあるのか?

  • 一度機械学習で分類されても、その後頻繁にサイトを利用するようになることで分類から除外されることはあるのか?

参考

(日本語訳) Migrating Garoon codebase to PHP 7

$
0
0

(※注 この記事は2017年8月18日に公開したMigrating Garoon codebase to PHP 7の日本語訳です。)

Garoon開発チームは 一年前にGaroonのソースコードのPHP 7移行作業を開始しました。 Garoonはソースコードも多かったり、もともとPHP 4で書いていたものをPHP 5に移行していたりするので、 移行作業は大変でしたが、移行することで大きな改善が行えました。 メリットの一つは性能改善です。GaroonをPHP 7 で動かしたときのベンチマークは、PHP 5.6と比べると33%改善しました。

そしてまた、php.netによると、PHP 5.6のアクティブサポートは2017年1月19日に終了しています。 ソース: http://php.net/supported-versions.php

この記事では、Garoon開発チームの遭遇した現象と、どうやってPHP 7に移行したかをお伝えします。

互換性のない変更を検出するためのツール

PHP 5から PHP 7に移行するとき、ソースコード全体から"下位互換性のない変更"を見つける必要がありました。私たちのコードがPHP 7で正しく動作することを確認するためです。 ソースコードを調べてPHP 7で動かすために修正が必要なコードを指摘してくれるツールがいくつかあります。その中にPhanとLintがあります

Phan

PhanはPHP用の静的解析ツールです。MITライセンスで公開されています。

環境の準備

PHP 7がインストールされた CentOSマシンを用意します。それから、以下のコマンドでcomposerをインストールします:

curl \-sS https://getcomposer.org/installer \| php \-\- \--install-dir=/usr/local/bin \--filename=composer

Phanとphp-ast拡張のインストール

まず、php-astのソースコードをcloneします:

git clone https://github.com/nikic/php-ast.git

次に、php-ast拡張をビルドして、phpに追加します。以下のコマンドを順番に実行してください。

cd php-ast
phpize
./configure
make install
echo 'extension=ast.so' > /etc/php.ini

それから、Phanをインストールして以下のコマンドで実行してください:

git clone https://github.com/etsy/phan.git
cd phan
composer install
./test
ln \-s /phan/phan /usr/local/bin/phan

Phanを実行して下位互換性のない変更を見つける

私たちは以下の内容のようなbashファイル(例: testPhan.sh)を作成しました:

COMMAND="phan \--backward-compatibility-checks \--ignore-undeclared \--quick"
find /repo/source \-type f \-regex '.*\.\(php\)' \-print0 \| xargs \-0 \-n1 \-P 1 \-I % bash \-c "$COMMAND % "

ファイル中の"/repo/source"をチェック対象のソースコードのパスに変更してください。それから実行します:

sh testPhan.sh

Lint

LintはPHPのコマンドラインオプションです。PHPの文法チェックに使われます。

前述のCentOSのマシンで以下のコマンドを実行し、PHPのソースコードをLintでチェックしました:

find . -name "*.php" -print0 | xargs -0 -n1 -P8 php -l

E_STRICT通知の深刻度の変更

E_STRICT通知の深刻度がPHP 7で変更されています。 すべてのE_STRICT通知がほかのレベルに移動しています。

状況 新しいレベル / 挙動
Indexing by a resource E_NOTICE
Abstract static methods Notice removed, triggers no error
"Redefining" a constructor Notice removed, triggers no error
Signature mismatch during inheritance E_WARNING
Same (compatible) property in two used traits Notice removed, triggers no error
Accessing static property non-statically E_NOTICE
Only variables should be assigned by reference E_NOTICE
Only variables should be passed by reference E_NOTICE
Calling non-static methods statically E_DEPRECATED

私たちのコードでもこれらのいくつかは影響がありました。

Signature mismatch during inheritance

"Signature mismatch during inheritance"通知は以下のようなケースで通常発生します: 一つ目のケースは、関数/メソッドのパラメータの数が継承時に異なる場合です。例:

<?phpclass Foo{function method($a){}}class Bar extends Foo{function method(){}}

上記の例の出力結果はこちらです:

Warning: Declaration of Bar::method() should be compatible with Foo::method($a) in /in/YoDHq on line 11

この例の実行結果はこちらで確認できます。

二つ目のケースは、関数/メソッドのパラメータの型が継承時に異なる場合です。例:

<?phpclass Foo{function method($a){}}class Bar extends Foo{function method(array$a){}}

上記の例の出力結果はこちらです:

Warning: Declaration of Bar::method(array $a) should be compatible with Foo::method($a) in /in/fSIbS on line 11

この例の実行結果はこちらで確認できます。

私たちはPhanを使ってコードをチェックし、PhanSignatureMismatch や PhanSignatureMismatchInternal として検知された問題を修正しました。

このタイプの問題の修正方法は、変更対象の基底クラスやサブクラスの中のロジックに依存します。

Only variables should be assigned by reference

例:

<?phperror_reporting(E_ALL);
function foo(){return'string';
}$temp=& foo();

上記の例の出力結果は以下のようになります:

Notice: Only variables should be assigned by reference in /in/vXUIZ on line 6

この例の実行結果はこちらで確認できます。

上の例では、'&'演算子が"Only variables should be assigned by reference"というE_NOTICEを引き起こしています。PHP 7の環境でコードがコンパイルされた場合は、エラーが検出されてしまうので、以下のように'&'演算子を削除して修正する必要があります:

<?phperror_reporting(E_ALL);
function foo(){return'string';
}$temp= foo();

しかし、私たちのコードには'&'演算子がたくさん使われており、すべて修正するには時間がかかりそうなことがわかりました。 この問題を解決するため、CentOS上にあるツールを導入しました。 まずはじめに、E_NOTICEメッセージをphp_error.logに出力するため、以下の手順を行います:

1. 以下のスクリプトをwebアプリケーションに追加して、実行します:

set_error_handler(function($errno, $errstr, $errfile, $errline){
  file_put_contents('/tmp/php_error.log', implode(',', [$errno, $errstr, $errfile, $errline]) . PHP_EOL, FILE_APPEND);
});

2. "php_error.log"は以下のようになっているはずです:

2048,Only variables should be assigned by reference,/var/www/project/code/xxx1.php,12
2048,Only variables should be assigned by reference,/var/www/project/code/xxx2.php,121
2048,Only variables should be assigned by reference,/var/www/project/code/xxx3.php,26
2048,Only variables should be assigned by reference,/var/www/project/code/xxx.php,194

このツールは以下の手順を実行します:

  1. tmpフォルダの中からsystem-private-から始まるフォルダの最新のものを見つけます。
  2. tmpフォルダ中のphp_error.logから"assigned by reference"という文字列をgrepで検索します。そして、ファイル名と行番号を一時的な結果として出力します。
  3. 2.の結果をもとに、"=&"、"= &"、"= & "を"="に置換します。
#!/bin/bash

systemd_private_name=$(ls -t1F /tmp/ | grep systemd-private-* | head -n1)
php_error_path="/tmp/${systemd_private_name}tmp/php_error.log"

if [ ! -f $php_error_path ]; then
    echo "File is not found"
    exit;
fi


grep "assigned by reference"  $php_error_path  | sort | uniq -c | while IFS=',' read -ra line ; do
    sed -ri ${line[3]}'s/(\$.+)(\s+=\s*&\s*)(.+())/\1 = \3/g'  ${line[2]}
done

Only variables should be passed by reference

PHP 7では、関数のパラメータを参照渡しにした場合、エラーが発生します。 この問題はPHPのフレームワークやユーザ定義メソッドを使用するときに発生します。

この問題を解決するため、私たちは関数の値を保存するための変数を宣言し、 直接呼ばれていた箇所にこれを渡しました。以下がその例です:

例: explodeで作られた配列をarray_popに渡すと、Strict Standards警告が発生する:

<?php$fruit=array_pop(explode(",", "Orange,Apple,strawberry"));
   echo$fruit;

修正後のコード:

<?php$fruits=explode(",", "Orange,Apple,strawberry");
   $fruit=array_pop($fruits);
   echo$fruit;

この例で注目していただきたいのは、explode関数用に変数を割り当ててからその変数の参照をarray_popに渡すことで、Strict Standards警告を回避している点です。

PHP フレームワークのメソッド

例:

<?php$file_name="abc.txt";
   $file_extension=end(explode('.', $file_name));

上記の例の出力結果はこちらです:

Notice: Only variables should be passed by reference in /in/Cv65t on line 3

この例の実行結果はこちらで確認できます。

修正後のコード:

<?php$tmp=explode('.', $file_name);
   $file_extension=end($tmp);

私たちはPhanを使ってコードをチェックし、PhanTypeNonVarPassByRef として検知された問題を修正しました。 しかし、Phanが調べるメソッドはPHPフレームワークのものだけです。 ユーザ定義関数は PhanTypeNonVarPassByRef として検知されません。以下の例をご覧ください。

ユーザ定義メソッド

例:

<?phpfunction getArray(){return[1, 2, 3];
}function squareArray(array&$a){foreach($aas&$v){$v**=2;
    }}// Generates a warning in PHP 7.
squareArray((getArray()));

上記の例の出力結果はこちらです:

Notice: Only variables should be passed by reference in in /in/HYONN on line 14

この例の実行結果はこちらで確認できます。

プロジェクト内のユーザ定義メソッドに対して調査する際は、notepad++などのエディタで正規表現による検索が利用できます。

function.*\&\s+\$.*\)$

上記の例の出力結果はこちらです:

E:\yourproject\comment_util.php (3 hits)
    Line 30:     function getFollowByUser( & $user, & $article )
    Line 61:     function _setNameRowSet( & $rowset, $inverse = FALSE )
    Line 119:     function _row2object( & $row )

参照メソッドを検索結果から見つけた後は、手動で関数呼び出しを修正します。

Calling non-static methods statically

staticではないメソッドのstatic呼び出しはPHP 7で非推奨になり、将来的には削除される可能性があります。

例:

<?phpclass foo {function bar(){echo'I am not static!';
    }}

foo::bar();

上記の例の出力結果はこちらです:

Deprecated: Non-static method foo::bar() should not be called statically in - on line 8
I am not static!

私たちはPhanを使ってコードをチェックし、PhanStaticCallToNonStatic として検知された問題を修正しました。 一番簡単な修正は、staticではない関数をすべてstaticな関数に変更することです。

PHP 4コンストラクタ

PHP 4コンストラクタは、クラス内で定義されているメソッドでクラスと同じ名前のものです。

PHP 7ではPHP 4コンストラクタが定義されていると、E_DEPRECATEDが発生します。 メソッド名がクラス名と一致し、クラスが名前空間内になく、PHP 5のコンストラクタ(__construct)がない場合、E_DEPRECATEDが発生します。

例:

<?phpclass Filter {function Filter(){}}new Filter();

出力:

Deprecated: Methods with the same name as their class will not be constructors in a future version of PHP; Filter has a deprecated constructor in /in/IDpi7 on line 3

この例の実行結果はこちらで確認できます。

以下のように、PHP 5のコンストラクタを使用する必要があります:

<?phpclass Filter {function__construct(){}}new Filter();

大きなプロジェクトの場合、手動での修正は時間がかかります。PHP-CS-Fixerという便利なツールがあります。これを使うと自動で修正することができます。 GaroonではPHP-CS-Fixerを使って500以上のファイルを修正しました。

このツールでPHP 4コンストラクタを修正する方法を記載します。下記のコードをPHP-CS-Fixer 2.2.1で実行してください。

1. まず、PHP-CS-Fixerの設定ファイルを作成します

.php_cs
<?php$source_dir='c:\repo\projectX\source';
$finder= PhpCsFixer\Finder::create()->in($source_dir)->files()->name('*.csp')->name('*.php')
;

return PhpCsFixer\Config::create()->setRiskyAllowed(true)->setRules(array('no_php4_constructor'=>true))->setFinder($finder)
;

注意: Garoonでは、PHPファイルの拡張子として".csp"を使用しているので、 ".csp"を設定ファイルに追加しています。

2. PHP-CS-Fixerを実行します

php php-cs-fixer.phar fix --config=.php_cs --verbose

このツールの詳細はこちらをご参照ください: https://github.com/FriendsOfPHP/PHP-CS-Fixer

内部関数の変更

PHP 7ではいくつかの内部関数が変更されています。substr()関数もその一つです。

例:

<?php$foo=substr("foo",3);
if($foo!==FALSE){echo"PHP 7\n";
    echogettype($foo); //string}else{echo"PHP 5\n";
    echogettype($foo); //boolean}

上記のコードの$foo変数の型は、PHP 5ではbooleanですが、PHP 7ではstringです

この例の実行結果はこちらで確認できます。

この問題を解決するため、strlen関数で文字長をチェックしました。

<?php$foo=substr("foo",3);
if(strlen($foo)==0){echo"Run on both PHP 5 and PHP 7\n";
    echogettype($foo); //boolean on PHP 5 and string on PHP 7}

この例の実行結果はこちらで確認できます。

まとめ

GaroonではPHP 5.6からPHP 7に移行することでパフォーマンスが向上し、コードも読みやすくなりました: 例えば、社内の性能検証では33%の性能向上が確認できています。 私たちは、移行作業を分けて一つずつ実施していました。これにより、起こりえる問題に対処しながら、短期間で移行作業を完了できました。

サイボウズサマーインターン2017 報告その3~SREコース

$
0
0

みなさんこんにちは。SREチームの内田(@uchan_nos)です。

今年もサイボウズではエンジニア向けのサマーインターンを行いました。 今年から「SREコース」が新設されたので、その実施報告を行います。

f:id:cybozuinsideout:20171019191621j:plain

インターンの概要

インターンの全体的な雰囲気は 報告その1~品質保証・セキュリティコースにあります。全体では3回に分けて実施されましたが、SREコースはもろもろの事情により第1回目(8月21日~8月25日)と第3回目(9月25日~9月29日)で実施しました。

SREコースでは、いくつかこちらでネタ案を提示し、学生さんに選んでもらうようにしました。 3人の学生さんに、この3ネタをやっていただきました。

  • 初動調査システムに機能を追加する
  • cybozu-go/kkokを使って、人間にやさしい通知システムを作る
  • 各種メトリクスを利用してボリュームの枯渇時期を予測する

次に参加される方の参考になるかもしれないので、3つのネタを簡単に紹介します。

初動調査システムに機能を追加する

f:id:cybozuinsideout:20171019191742j:plain:medium:left

初動調査システムは、SREチームが自社DC向けに開発しているシステムです。 障害1が発生すると、障害発生個所に関連した機材の状態を自動的に観測し、人間に通知してくれます。

このシステムに、サーバ機のハードウェア状態を検査するコマンドを実行させる機能を追加するというネタをやってもらいました。 ついでに、少し前から発生していた「VMへのSSHがなぜか失敗する」というバグの修正もやってもらいました。

異常が無くても通知する

もともとのネタの内容は、初動調査システムがハードウェア状態の調査コマンドを実行し、その結果を通知内容に含める、というものでした。

ネタの設計をするために初動調査システムのソースコードを読んでもらうと、あることに気付きました。 それは 初動調査システムはハードウェア状態の調査コマンドを実行しているが、普段はエラーが無いので何も出力がないという事実です。

ということで、内容を急きょ「エラーが無いときでも検査した事実を載せる」と方針転換し、実装してもらうことに。 ここから得られる教訓は 異常が無くても、異常が無いことを明示的に出力すべしということでしょう。 システムが自動でやってくれていることを、人間が再実行する無駄をなくすために大切なことですね。

kkokを使って、人間にやさしい通知システムを作る

f:id:cybozuinsideout:20171019192212j:plain:medium:left

cybozu-go/kkok2とは、SREチームが作っているOSSの1つで、メッセージをイイ感じに配送するサービスです。 障害発生時などに警告メッセージを送る需要があるのですが、そのメッセージングを制御したいという需要から生まれました。 例えば、今からメンテナンスするので警告が発生することが分かりきっている、というような場合に、手軽に警告メッセージを抑制したいです。

メッセージが3日連続したら通知する

cronで定期的に何らかの検査をして、エラーが見つかったら通知する、ということはよくあります。 本当はエラーを自動解決できるのが理想的ですが、そうなっていない場合も多々あります。

エラーがクリティカルなものであれば、エラーが発見されたときに通知を飛ばせば良いでしょう。 しかし、1回だけエラーになってもクリティカルではないが、エラーが一定以上続いたら気づきたい、というケースもままあります。

そういうケースで人間が通知を受け取ったときに「ええと、昨日も来てたっけ?」と、過去の通知を探すのは割とつらい作業です。 kkokを使って、N日間連続で同じ警告が来た時に人間に通知を飛ばす、というフィルタを試作していただきました。

ボリュームの枯渇時期を予測する

f:id:cybozuinsideout:20171019192242j:plain:medium:left

サイボウズクラウドには、毎日お客様のデータが溜まっていきます。 当然、ボリューム3の空き容量はどんどん減っていくので、ある閾値以下になったらボリュームを自動的に拡張するシステムが動いています。

ボリューム拡張をお客様のアクセスが多い時間帯に行うと性能が劣化する場合があるので、 自動拡張システムはアクセスが多くなる日中帯は避けて拡張を行います。 また、負荷が高い作業が行われているときは拡張しないなどの配慮がなされています。

自動拡張システムを監視する

まれに、それらの配慮が何日も発生してしまい、ボリューム拡張がされないことがあるかもしれません。 また、実は自動拡張システムにバグがあって全然拡張されない、という事態が発生する可能性もあります。 自動拡張が間に合わないペースでボリュームが消費されることもあり得ます。

ということで、ボリュームの空き容量の時系列データを利用し、向こう1カ月以内にボリュームが枯渇するかどうかを予測するプログラムを作成していただきました。 Jupyter Notebookで試作品を作ってもらい、良い感じに予測するプログラムが出来上がりました。

インターンの感想

どのネタもコーディングを含むもので、一部は我々のコードベースを読む必要があるものでした。 それを実質3日間でやり遂げる必要がありましたが、3人の学生さんはちゃんと成果を残していただけました。素晴らしい! しかも、一部の成果物は実際に本番環境に取り込まれ、現在も元気に動いております。

たくさんの学生さんと触れ合うことができ、メンターとしても非常に楽しいインターンでした。 3日間で何らかの成果を出してもらうためのマネジメント方法を探求したりだとか、いろいろ学ばせていただきました。

3人の写真を見てみるとペンギンが高確率で出てきますね。 エンジニアはペンギンと触れ合いたくなるものだということでしょうか?


  1. モニタリング用URLへのアクセスのエラー率が閾値を超えたりすると障害とみなされます。

  2. 読み方は「ケーコック」。もちろん「警告」に由来しています。

  3. LinuxのLVMを利用して構成した論理ボリュームです。

Viewing all 681 articles
Browse latest View live