yusuke.blog https://yusuke.blog プログラムと、ゲームと、諸々と Wed, 25 Feb 2026 02:33:50 +0000 ja hourly 1 https://wordpress.org/?v=6.8.3 203514357 Jakarta EE&MicroProfileセミナー「Jakarta CDI特集(実践的活用方法とAI領域への拡張)」に参加しました #JakartaEE https://yusuke.blog/2026/02/25/3581 Wed, 25 Feb 2026 01:20:50 +0000 https://yusuke.blog/?p=3581 Jakarta EEの日本のコミュニティを新たに立ち上げるということで勉強会に参加しました。 CDIの誤解しがちな仕様と…

続きを読む

The post Jakarta EE&MicroProfileセミナー「Jakarta CDI特集(実践的活用方法とAI領域への拡張)」に参加しました #JakartaEE first appeared on yusuke.blog.]]>
Jakarta EEの日本のコミュニティを新たに立ち上げるということで勉強会に参加しました。

CDIの誤解しがちな仕様とその対処TIPS / 吉崎 太清 (アクセンチュア)

CDIをアプリケーションから使う際にハマりがちな罠の説明。

  1. CDIでインジェクトする対象のコンポーネントにpublicなフィールドがあると、デプロイ時に警告が出るけれども原因が分かりにくいといういう話。GitHubにサンプルコードを公開してくれているので、IntelliJ IDEAで開いて見たところ、デプロイしなくてもエディタ内で警告してくれました。
    @yusuke デプロイしなくてもIDEが警告してくれた #JakartaEE
  2. CDIのコンポーネントをフレームワークにInjectしてもらわず、アプリケーションから取得した場合、明示的に破棄しないとメモリリークするという話。
    Injectしてもらわずに自分から取得するケースってかなりレアなので「陥りがちな罠」という感じではない気がしたが、知識としてはもっておくと有用。

LangChain4jとは一味違うLangChain4j-CDI / 数村 憲治@kkzr(富士通株式会社)


資料

  1. LangChain4jの歴史。LangChainはPythonからChatGPTなどのLLMを利用するためのライブラリ。LangChain4jは同じような役割のJava版。「移植」ではなく、似た機能を持つ独自実装だそう。
  2. LangChain4j-CDIの紹介。JakartaでAI関連機能を策定するかどうかはかなり議論があり、まだ時期尚早という声も多かったものの、Jakarta EEにはまだ組み込まない形で独立仕様として策定していこうという方向になっている。
    What’s Up With Open Standard Enterprise Java and AI?
    リリースされたばかりのLangChain4j-CDIで、n代目の大統領や首相、その出身地を質問できるアプリケーションのデモ。利用するLLMをハードコードすることなく、LLMの差し替えが可能であったり、LLMに接続できない場合のフォールバック動作、プロンプトインジェクションを防ぐInput Guardrail、予期しないレスポンスをユーザーに提示してしまうことを防ぐOutput Guardrailなどが紹介された。
    Understanding LangChain4j Guardrails
    プロンプトインジェクションや、DoS攻撃などはLLMを使ったアプリケーションではかなり気になるところ。今回のデモでは入力は整数しか受け付けない作りなので、Input Guardrailは不要と思われるけれども、入力を自由に受け付けられるアプリケーションを実装するときはInput Guradrailの作りがかなり肝となりそう。

スライドのそこかしこに登場する丸みを帯びたゆるDukeが可愛かった。

懇親会

参加者20名くらい?懇親会前にジャンケン大会でMicroProfileのパーカーを頂いた。Lサイズを選んだがアメリカンのLサイズで、ゆったりだった。次回の勉強会に着て行く。

吉崎さんが追加の講演をしながら、懇親会も並行する感じでした。美味しくピザをいただきました。会場、懇親会の飲み物食べ物を提供してくださったレッドハットありがとう。
懇親会で私はずっと@_vermeer_と、AIを使った開発でシステム開発の人員は減らせそうだね、とか大規模開発では打ち合わせがボトルネックになりそうだけどもどういう流れで開発を進めていけばいいんだろうか、とか、MSX楽しいね、とか話していました。

感想

Spring Bootに押され気味のJakarta EE。基幹システムでは古くから使われているが、今後どうなんだろうという感じ。Broadcom、VMwareの今後の以降が知れないので、Jakartaにも頑張って欲しいが、参加者も講演者もJakartaの今後はどうなんだろうね、とちょっと不安交じりでもありました。
あと、標準化されており実装は各々が出来る、とはいえコンポーネントによっては各メーカー同じ実装を使っているケースも多いので、標準化ってなんなんだろうね?とか、LibertyとWildfly/JBoss EAPはそろそろ合流しないのかね?とかも話題になりました。
いずれにせよ、選択肢が多いというJakarta EEのメリットはあるので今後の繁栄を願ってやみません。

The post Jakarta EE&MicroProfileセミナー「Jakarta CDI特集(実践的活用方法とAI領域への拡張)」に参加しました #JakartaEE first appeared on yusuke.blog.]]>
3581
Gradleを9.0.0にアップデートしたらFailed to load JUnit Platformと出たのを直したメモ https://yusuke.blog/2025/08/03/3530 Sun, 03 Aug 2025 08:11:27 +0000 https://yusuke.blog/?p=3530 Gradle 9.0.0がリリースされました。手始めにシンプルなプロジェクトであるBusinessCalendar4Jの…

続きを読む

The post Gradleを9.0.0にアップデートしたらFailed to load JUnit Platformと出たのを直したメモ first appeared on yusuke.blog.]]>
Gradle 9.0.0がリリースされました。手始めにシンプルなプロジェクトであるBusinessCalendar4Jのバージョンを上げてみました。

Gradleのアップデート

IntelliJ IDEAであればCtrlを2回押して”gradlew wrapper --gradle-version=9.0.0“を入力すればOK。

テストを実行

無事ビルド、テスト実行できるか試してみたところ”Could not start Gradle Test Executor 2: Failed to load JUnit Platform. Please ensure that the JUnit Platform is available on the test runtime classpath.”と出て失敗しました。

問題の解決方法についてはURLが提示されていますが、エラーメッセージでもGradle 9: Failed to load JUnit Platform. Please ensure that the JUnit Platform is available on the test runtime classpath. #34512がヒットしました。どちらも同じことが書いてあって、

testRuntimeOnly("org.junit.platform:junit-platform-launcher")

を追加すれば良いそうです。

というわけで、Gradle 9.0.0の新機能は何も活かしていないけれども無事テスト実行できるようになりました。

9.0.0にアップデートしたコミットはこちら

The post Gradleを9.0.0にアップデートしたらFailed to load JUnit Platformと出たのを直したメモ first appeared on yusuke.blog.]]>
3530
カンファレンスのスポンサーブース設営のお勧めアイテム その3 – バナー https://yusuke.blog/2025/06/10/3505 Tue, 10 Jun 2025 04:29:43 +0000 https://yusuke.blog/?p=3505 カンファレンスのブースではバナーを設置する会社も多いです。 自立式バナーは自動的に巻いてくれて引っ張り上げるだけのタイプ…

続きを読む

The post カンファレンスのスポンサーブース設営のお勧めアイテム その3 – バナー first appeared on yusuke.blog.]]>
カンファレンスのブースではバナーを設置する会社も多いです。
自立式バナーは自動的に巻いてくれて引っ張り上げるだけのタイプ、支柱を組み立てるタイプなど様々あります。

サムライズムではこれまで3,4種類の仕様のバナーを試してみた経験から、旗・幕ドットコムの「ブルーバナーSS120」に落ち着いています。
旗・幕ドットコム – 展示会ブース用バナースタンド – ブルーバナーSS120
価格はこの原稿を書いている時点で防炎加工付で2万円ほど。サイズ違いのバリエーションもあります。

組み立てが簡単で軽量、そして安定感と揃いも揃って間違いないです。
これまたいつもレビューを書いているくらいお気に入りです。

自動巻きのタイプは設置は簡単ですが少し重くれかさばること、収納時に歪んだ状態で巻かれるとバナーが破れたりシワが入ってしまったりすること、勢い良く巻かれると壊れてしまうことがある、など、実は扱いに少し気を使います。慣れない人が手を滑らして壊してしまうシーンをこれまで何度も見ています。
バナーを扱う人が固定されている場合は良いかもしれませんが、毎回誰が設置するか決まっていない会社では自動巻きタイプはオススメしません。

また、「ブルーバナーSS120」は、什器本体はそのままに、バナー部分だけど新たに印刷してもらって差し替えることも可能です。

自動巻きタイプのバナーの具の差し換えは多くの場合出来ません。

The post カンファレンスのスポンサーブース設営のお勧めアイテム その3 – バナー first appeared on yusuke.blog.]]>
3505
カンファレンスのスポンサーブース設営のお勧めアイテム その2 – テーブルクロスとテーブルクロス止め https://yusuke.blog/2025/06/10/3497 Tue, 10 Jun 2025 03:10:45 +0000 https://yusuke.blog/?p=3497 多くのブースではテーブルクロスをかけています。 ブースのテーブルサイズは多くの場合180cmx60cm、または180cm…

続きを読む

The post カンファレンスのスポンサーブース設営のお勧めアイテム その2 – テーブルクロスとテーブルクロス止め first appeared on yusuke.blog.]]>
多くのブースではテーブルクロスをかけています。
ブースのテーブルサイズは多くの場合180cmx60cm、または180cmx45cmですが、それ以外の場合もあります。テーブルクロスをどれくらいのサイズにするのか、どこの業者にお願いするのか、迷う人は多いでしょう。

サムライズムでは

サイズ: 横3,000mm x 縦1,450mm
生地: バンテン(厚めの木綿生地)
防炎加工: あり

という仕様でハクロマーク製作所の旗・幕ドットコムでいつもお願いしています。
いつも一手間かけてレビューを送っているほど、抜群に信頼しています。対応もスムースで間違いないです。

旗・幕ドットコム – 展示会用オリジナルテーブルクロスの印刷・作成
この仕様を、記事執筆時点で見積もると税別約5万円となります。後で説明するテーブルクロス止めも一緒に注文するのをお忘れ無く。
他の生地にすれば少し割安にもできますが、長持ちすること、見栄えや綺麗なこと、透けないことからバンテンがお勧めです。
薄い透ける生地で、後ろに窓があるとテーブル下に置いてあるバッグや備品が見えてしまうことがあります。

また、防炎加工のオプションもつけておきましょう。企業が開催する大きな会場ですと消防法の関係で防炎加工が必須となります。防炎加工は洗濯すると落ちてしまうので気を付けてください。
防炎効果の期間や、後から再度防炎加工できるか、など詳しい情報がハクロマーク製作所のYouTubeで解説されていますので合わせてご参照ください。

テーブルクロスはテーブルにかけるだけだと、端がダラっとしてしまいます。かならずテーブルクロス止めを使うようにしましょう。クロスがピッチリと箱形になって綺麗です。
Amazonやヨドバシでも買えます、ハクロマークならばテーブルクロス本体と一緒に注文出来ます。
旗・幕ドットコム – テーブルクロス止め
テーブルクロス止めの使い方はこちら:

The post カンファレンスのスポンサーブース設営のお勧めアイテム その2 – テーブルクロスとテーブルクロス止め first appeared on yusuke.blog.]]>
3497
カンファレンスのスポンサーブース設営のお勧めアイテム その1 – 折りたたみコンテナ https://yusuke.blog/2025/06/10/3495 Tue, 10 Jun 2025 02:41:40 +0000 https://yusuke.blog/?p=3495 自分の会社ではよくカンファレンスに協賛しており、年間10〜20回くらいブース運営をしています。 回数をこなす分、段々と運…

続きを読む

The post カンファレンスのスポンサーブース設営のお勧めアイテム その1 – 折りたたみコンテナ first appeared on yusuke.blog.]]>
自分の会社ではよくカンファレンスに協賛しており、年間10〜20回くらいブース運営をしています。

回数をこなす分、段々と運営用の物品が揃ってきましたのでお勧めの品物をアフィリエイトリンクを添えて書き連ねていきたいと思います。

まず最初は折りたたみコンテナ。

・松本産業 折りたたみコンテナ 50L

最初、展示用物品はダンボールに入れていましたが、2,3回も送るとボロボロになって穴が空いてきます。プラスチックの折りたたみコンテナならば何度も使えます。プラスチックだと衝撃でヒビが入ったり穴が空いたりするのでは?と心配があるかもしれませんが、比較的柔軟性のある素材なのでそう簡単には壊れません。たまーにネジが飛び出して来る事がありますが、プラスねじで軽く締めれば当面は大丈夫。

コンテナは蓋の継ぎ目を側面2箇所、上面1箇所、養生テープで止めれば輸送中に開いてしまうこともありません。養生テープは展示物をちょっと固定するとか、壊れた展示物を簡易補修するとか、何かと使います。まとめ買いしておきましょう。
・ダイヤテックス パイオラン 塗装・建築養生用テープ Y-09-CL 50mm×25m(5巻パック)

撤収時、養生テープでコンテナを閉じたところ養生テープを入れ忘れる、なんてことは良くあるのでお気をつけください。
先だってコンテナの幅に合わせて3本用意して、机に端っこだけ裏返して貼り付けておけばワシャワシャになりません。

また、養生テープはステッカー類がそこそこ剥がれやすい素材なので、上面に貼っておくと送り状などを綺麗に剥がすことが出来ます。

養生テープに貼られたステッカーを剥がすのはなかなかASMRです。

The post カンファレンスのスポンサーブース設営のお勧めアイテム その1 – 折りたたみコンテナ first appeared on yusuke.blog.]]>
3495
ワンライナーで認証付のプロキシサーバをDockerとSquidで立てる https://yusuke.blog/2024/10/02/3438 Wed, 02 Oct 2024 06:42:33 +0000 https://yusuke.blog/?p=3438 アプリケーションがプロキシを使ってくれるかテストをしたかったので、Dockerでsquidを立てました。 Squidは伝…

続きを読む

The post ワンライナーで認証付のプロキシサーバをDockerとSquidで立てる first appeared on yusuke.blog.]]>
アプリケーションがプロキシを使ってくれるかテストをしたかったので、Dockerでsquidを立てました。
Squidは伝統的なプロキシサーバです。
以下のコマンドで3128番でユーザID: user1、パスワード: password1 で認証されるプロキシサーバが立ちます。

 

docker stop squid-proxy;docker rm squid-proxy;docker run -d --name squid-proxy -p 3128:3128 sameersbn/squid:latest bash -c "\
apt-get update && \
apt-get install -y apache2-utils && \
htpasswd -b -c /etc/squid/passwords user1 password1 && \
chown proxy:proxy /etc/squid/passwords && \
chown proxy:proxy /dev/stdout && \
chmod 640 /etc/squid/passwords && \
echo 'http_port 3128
auth_param basic program /usr/lib/squid/basic_ncsa_auth /etc/squid/passwords
auth_param basic realm Squid Proxy
acl authenticated proxy_auth REQUIRED
http_access allow authenticated
access_log stdio:/proc/self/fd/1 squid
cache_log stdio:/proc/self/fd/1
cache_store_log stdio:/proc/self/fd/1' > /etc/squid/squid.conf && \
squid -N"; docker logs -f squid-proxy

もちろん再現性を高めたり、細かく設定を変えたりするにはDockerファイルを作った方がいいです。

認証が要らない場合は以下で。

docker stop squid-proxy;docker rm squid-proxy;docker run -d --name squid-proxy -p 3128:3128 sameersbn/squid:latest bash -c "\
chown proxy:proxy /dev/stdout && \
echo 'http_port 3128
http_access allow all
access_log stdio:/proc/self/fd/1 squid
cache_log stdio:/proc/self/fd/1
cache_store_log stdio:/proc/self/fd/1' > /etc/squid/squid.conf && \
squid -N"; docker logs -f squid-proxy
The post ワンライナーで認証付のプロキシサーバをDockerとSquidで立てる first appeared on yusuke.blog.]]>
3438
JavaMailでSMTPS/STARTTLSを使う場合はmail.smtp.ssl.checkserveridentityを設定する必要がある https://yusuke.blog/2024/03/29/3415 Fri, 29 Mar 2024 02:07:22 +0000 https://yusuke.blog/?p=3415 まとめ JavaMailでSMTPS/STARTLSを使う場合は “mail.smtp.ssl.checks…

続きを読む

The post JavaMailでSMTPS/STARTTLSを使う場合はmail.smtp.ssl.checkserveridentityを設定する必要がある first appeared on yusuke.blog.]]>
まとめ

JavaMailでSMTPS/STARTLSを使う場合は “mail.smtp.ssl.checkserveridentity” を明示的に “true” に設定しましょう。デフォルトではホスト名検証されません。

JavaMailとは

JavaMailはJavaからメールの送受信を行うためのAPIです。

たとえば以下のようなコードでGMailのSMTPサーバを使ってメールを送信することができます。

import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.io.UnsupportedEncodingException;
import java.util.Properties;


void main() throws MessagingException, UnsupportedEncodingException {
    Properties props = getProperties();
    Session session = Session.getInstance(props, new Authenticator() {
        protected PasswordAuthentication getPasswordAuthentication() {
            return new PasswordAuthentication("[email protected]", "password");
        }
    });
    String encoding = "UTF-8";
    MimeMessage mimeMessage = new MimeMessage(session);
    mimeMessage.setHeader("Content-Type", STR."text/plain; charset=\{encoding}");
    mimeMessage.setFrom(new InternetAddress("[email protected]", "[email protected]", encoding));
    mimeMessage.setRecipients(Message.RecipientType.TO, new Address[]{new InternetAddress("[email protected]")});
    mimeMessage.setRecipients(Message.RecipientType.CC, "[email protected]");
    mimeMessage.setRecipients(Message.RecipientType.BCC
            , new Address[]{new InternetAddress("[email protected]")});
    mimeMessage.setReplyTo(new Address[]{new InternetAddress("[email protected]")});
    mimeMessage.setSubject("件名", encoding);

    mimeMessage.setText("本文", encoding);
    mimeMessage.setHeader("Content-Transfer-Encoding", "7bit");
    mimeMessage.setHeader("Content-Type", STR."text/plain; charset=\{encoding}");

    Transport.send(mimeMessage);
}

private static Properties getProperties() {
    Properties props = new Properties();
    props.setProperty("mail.smtp.host", "smtp.gmail.com");
// SMTPS
//    props.setProperty("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
//    props.setProperty("mail.smtp.socketFactory.fallback", "false");
//    props.setProperty("mail.smtp.port", "465");

// STARTTLS
    props.setProperty("mail.smtp.port", "587");
    props.put("mail.smtp.starttls.enable", "true");

    props.setProperty("mail.smtp.auth", "true");
    props.setProperty("mail.smtp.ssl.checkserveridentity", "true");
    props.setProperty("mail.debug", "true");
    return props;
}

587? 464?

getPropertiesで設定している587はSTARTTLSという、セッション確立後にTLSを確立して安全性を確保する仕組みで使われるポート番号です。465番はセッション確立当初からTLS接続を行う場合に使います。
TLSの意義は暗号化することで盗聴から守ることに加えて、証明書を検証することで中間者/MITM攻撃を防ぐことにあります。つまり通信する相手が成りすましをしていないことを確認できます。
証明書の有効期限の切れたWebサイトや、ドメイン名を変えたのに別のドメインの証明書を使っているサイトなどにアクセスすると警告が出るのはそのせいです。

JavaMailはデフォルトでホスト名の検証を行わない

JavaMailは歴史のあるAPIで、SSLのサポートは後から追加されました。互換性維持のため、デフォルトではホスト名の検証を行わないそうです。
Notes for use of SSL with JavaMail
なので、SMTPS/STARTTLSで接続する際は先のコード例のように
props.setProperty(“mail.smtp.ssl.checkserveridentity”, “true”);
と、”mail.smtp.ssl.checkserveridentity”プロパティを設定する必要があります。
設定しなくてもメールは送信できるし、サーバサイドで使われることの多いJavaアプリケーションにたいして中間者攻撃を実施できるケースは少ないです。が、可能性が低いこと=ホスト名検証をしなくて良いこと、にはなりません。

The post JavaMailでSMTPS/STARTTLSを使う場合はmail.smtp.ssl.checkserveridentityを設定する必要がある first appeared on yusuke.blog.]]>
3415
Files#readStringでShift_JISで(UTF-8以外の多くのエンコーディングで?)保存されたテキストファイルをJava 22で読み込むと化ける現象とその回避策 https://yusuke.blog/2024/03/21/3398 Thu, 21 Mar 2024 01:38:30 +0000 https://yusuke.blog/?p=3398 JDK 22がリリースされました。早速アップデートしようと思ったらテストが一つ落ちることに気が付きました。調べたところ、…

続きを読む

The post Files#readStringでShift_JISで(UTF-8以外の多くのエンコーディングで?)保存されたテキストファイルをJava 22で読み込むと化ける現象とその回避策 first appeared on yusuke.blog.]]>
JDK 22がリリースされました。早速アップデートしようと思ったらテストが一つ落ちることに気が付きました。調べたところ、Shift_JISのファイル読み込みで文字化けが発生していることがわかりました。Java 22のバグのような気がします。以下のコードで再現できます。

package one.cafebabe;

import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;

public class Main {
    public static void main(String[] args) throws IOException {
        System.out.println("Java Version:" + System.getProperty("java.version"));

        String[] encodings = {"UTF-8", "SJIS"};
        for (String encoding : encodings) {
            test(encoding);
        }
    }

    static void test(String encoding) throws IOException {
        System.out.println("---------Testing:" + encoding);
        Charset charset = Charset.forName(encoding);
        Path path = Path.of(encoding + "_encoded.txt");
        String originalContent = "日本語です";
        byte[] encodedBytes = originalContent.getBytes(charset);
        String decodedString = new String(encodedBytes, charset);
        System.out.println(decodedString);
        System.out.println("Decoded string matches:" + decodedString.equals(originalContent));

        Files.writeString(path, originalContent, charset);
        String read = Files.readString(path, charset);
        System.out.println(read);
        boolean matches = read.equals(originalContent);
        System.out.println("Content from file matches:" + matches);

    }
}

“日本語です”という文字列をShift_JISでファイルに書き出し、読み込むだけです。

Java 22だと実行結果が以下のようになります。バイト列で書き出して、new String()で復元した場合は問題ありませんが、Files.readStringで読み込んだ場合は化けているのが分かります。

Java Version:22
日本語です
Decoded string matches:true
åe,gžŠg0Y0
Content from file matches:false

“日本語です”という文字列をShift_JISでファイルに書き出し、読み込むだけです。

Java 21は以下のように化けません。

Java Version:21.0.2
日本語です
Decoded string matches:true
日本語です
Content from file matches:true

Java 22は長期サポート版(LTS)ではないので、移行する人は多くないと思いますが、日本で広く使われるエンコーディングなのでご利用になる方はご注意ください。UTF-8エンコーディングの読み込みでは文字化けしません。また、Shift_JIS以外については確認していません。
根本原因について調査はしません。興味のある方は是非追ってみてください。

この現象は既にbugreport.java.comへ報告済みです。

確認したところShift_JISに限らず、UTF-8以外の多くのエンコーディングで文字化けするようです。

さらに確認したところ、InputStreamReaderを使った場合は化けず、Files#readStringを使った場合に化けることも分かりました。new String()で化けていなかったことからそこまで心配していませんでしたが、コアライブラリ全般に渡るバグではなくて、ピンポイントにFiles#readStringの問題かもしれませんね。

追記:

バグ登録されました。

JDK-8328714 : Shift_JIS encoded content gets garbled with Java 22

追記:

Oracleから返事があり、リリースノートに記載の既知の問題であるとのことです。リリースノートを確認するのは基本ですね。お恥ずかしい!しかしこんな問題がテストで検出されず、既知の問題として認識されたままリリースされるとは想像していませんでした……。というわけで、リリースノートに記載の通り、-XX:-CompactStrings オプションをつけることで回避が出来ることを確認しました。ちなみに@skrbにより指摘していただいた件がビンゴでした(この修正がリグレッションを産んだのでは?という予想だったみたいですが、まだ取り込まれていなかったようです)。

The post Files#readStringでShift_JISで(UTF-8以外の多くのエンコーディングで?)保存されたテキストファイルをJava 22で読み込むと化ける現象とその回避策 first appeared on yusuke.blog.]]>
3398
Google WorkspaceやZendeskから送信されるメールが迷惑メールとならないようにする: SPF、DKIM、DMARCの設定の覚書 https://yusuke.blog/2024/01/18/3362 Thu, 18 Jan 2024 09:14:25 +0000 https://yusuke.blog/?p=3362 神奈川県の入試出願システムからのメールがGmailで弾かれてしまうという問題が最近話題になりました。 ・高校入試の出願シ…

続きを読む

The post Google WorkspaceやZendeskから送信されるメールが迷惑メールとならないようにする: SPF、DKIM、DMARCの設定の覚書 first appeared on yusuke.blog.]]>
神奈川県の入試出願システムからのメールがGmailで弾かれてしまうという問題が最近話題になりました。
高校入試の出願システム、Gmailにメール届かず……神奈川県、受験生に「@gmail.com以外のアドレス使って」

メールを配信する仕組みは当初性善説に基づいて設計されたため、送信元や時刻を偽ったり、途中で文面が改善されていたりしても検証する仕組みがありませんでした。
現在はSPF、DKIM、DMARCといった技術で、送信元の詐称や改竄を防ぐことが出来るようになっており、これらの設定をしていないと迷惑メールとして弾かれたり、受信が拒否されたりといったことが起こりやすくなります。
中でもSPFは最低限設定しておかないと簡単に迷惑メールに振り分けられます。

SPF、DKIM、DMARCについて詳しくは世の中にいくらでも解説がありますが、自分の理解のために簡単にまとめました。

SPF

第三者が勝手なサーバからメールを配信したものを検出できるようにする仕組み。

紫外線をどれくらい防げるかの度合い、”Sun Protection Factor”、とは別で”Sender Policy Framework”の略。特定のドメインのメールがどのサーバから配信されるのかをDNSで事前に設定しておく。
ドメインで事前に設定されていないサーバから送られてくるメールは詐欺だろうと検出できる。
設定はdigコマンドでTXTレコードを引くと確認できる。

% dig samuraism.com TXT
<略>
samuraism.com.          300     IN      TXT     "v=spf1 include:_spf.google.com include:mail.zendesk.com ~all"

この例では具体的な送信サーバはGoogleやZendeskが設定しているものを引用するようになっている。

DKIM

メールの改竄を検出する仕組み。

送信元でメール内容を秘密鍵を使って署名を生成し、ヘッダ “Dkim-Signature”に記し、受信者はDNSから公開鍵を取得して署名を検出することで改竄を検出できる。

DKIMの鍵の作り方、設定方法

秘密鍵、公開鍵は以下のようなopensslコマンドで生成できる。

% openssl genrsa -out private.pem 2048
% openssl rsa -in private.pem -out public.pem -pubout -outform PEM

公開鍵(public.pem)—–BEGIN PUBLIC KEY—– / —–END PUBLIC KEY—–を除く部分を[セレクタ]._domainkey.[ドメイン]というTXTレコードに設定する。
DNSのレコードは255文字を超える場合は以下のように、255文字以内に区切ってダブルクオートで囲い、スペースで区切った形で設定する必要がある。
“255文字までの文字列1” “255文字までの文字列2”

設定した公開鍵は、例えば鍵のセレクタがgmaildkim、ドメインがsamuraism.comであれば以下のdigコマンドで確認できる。

dig gmaildkim._domainkey.samuraism.com TXT

SendGridにおけるDKIMの設定方法

覚書をまとめるまでも無くSendGrid/構造計画研究所のページを見るのが一番!
SendGrid ユーザマニュアル > Domain Authentication(SPF/DKIM設定)の設定方法

DNSレコードさえ正しく指定しておけば、SendGridのSMTPサーバが署名を行ってくれるので、アプリケーションでDkim-Signatureヘッダを指定する必要はありません。

メール回りの疑問は構造計画研究所のサイトを見れば間違いなく解決します。

Google WorkspaceにおけるDKIMの鍵の作り方、設定方法

Google Workspaceの管理画面の[アプリ>Gmail>メールの認証]から設定する。

「新しいレコードを生成」を押して表示される「新しいレコードを生成」ダイアログで、DKIMの鍵長(現在は2048ビットが推奨されるらしい)を選び、任意のプレフィックス(セレクタ)を指定して生成する。

生成された鍵をDNSで指定(255文字を超えているのでダブルクオートやスペースで区切る必要がある)して、「認証を開始」を押すと有効になる。
Gmailから送るメールも、アプリケーションからGoogleのSMTPサーバ smtp.gmail.com を使って送る場合も自動的に署名(Dkim-Signature)が付加されるようになります。
つまりアプリケーションでDkim-Signatureヘッダを生成/設定する必要はありません。

ZendeskにおけるDKIMの設定方法

zendesk1._domainkey.[ドメイン名] → zendesk1._domainkey.zendesk.com
zendesk2._domainkey.[ドメイン名] → zendesk2._domainkey.zendesk.com
というCNAMEレコードを設定する。
管理画面の[Talkとメール>メールアドレス>DKIMのカスタムドメイン>有効にする]にチェックを入れる。
Zendesk – DKIMを使用したメールのデジタル署名

DKIMの設定確認方法

DNSの設定確認

DKIM Record Checkerでドメインとセレクタ名を入れてチェックできる。

DMARCとは

DMARCはメールの認証に失敗した場合にどのように処理するか(none:なにもしない、quarantine:隔離する≒迷惑メールフォルダに振り分けられる、reject:受信を拒否する)を指定したり、認証に失敗した集計レポートを送るメールアドレスの送信先を指定したりできる。
DMARCはDNSに _dmarc.[ドメイン名] というTXTレコードで設定する。
digコマンドではこう確認する

% dig txt _dmarc.samuraism.com              

; <<>> DiG 9.10.6 <<>> txt _dmarc.samuraism.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 32891
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;_dmarc.samuraism.com.          IN      TXT

;; ANSWER SECTION:
_dmarc.samuraism.com.   3600    IN      TXT     "v=DMARC1; p=quarantine; rua=mailto:[email protected]; pct=20"

;; Query time: 78 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Thu Jan 18 18:08:08 JST 2024
;; MSG SIZE  rcvd: 132

この場合は p= で、認証に失敗した場合は隔離、rua= で集計レポートは[email protected]に送信、pct= でDMARCによる認証は全体の20%に適用、という設定になっている。
pctは1〜100(%)を指定でき、何も指定しない場合はデフォルトの100が適用される。設定に問題があり、メールが拒絶されまくってしまうような事態を防ぎたければ低い値を設定し、最終的に100か、指定なしにする。

DMARCの確認

DMARC Record Checkerで確認できる。

これはあくまでDNSレコードの設定内容を確認するだけで、SPFやDKIMが適用されてメールが正しく認証されていることを確認しているわけではない。

署名の確認

メールを外部に送信し、Authentication-Resultsヘッダを見る。
SPF、DKIM、DMARC、それぞれ検証に成功していれば以下のように spf=pass、dkim=pass、dmarc=passと書かれている。

Authentication-Results: bimi.icloud.com; bimi=skipped reason="insufficient dmarc"
Authentication-Results: arc.icloud.com; arc=none
Authentication-Results: dmarc.icloud.com; dmarc=pass header.from=samuraism.com
Authentication-Results: dkim-verifier.icloud.com; dkim=pass (2048-bit key) header.d=samuraism.com [email protected] header.b=Q9wPckpv
Authentication-Results: spf.icloud.com; spf=pass (spf.icloud.com: domain of [email protected] designates 209.85.210.45 as permitted sender) [email protected]

また、Dkim-Signatureヘッダの d= にfromアドレスのドメインが記載されていることも確認。つまりFrom:[email protected]であれば d=samuraism.com となっているべき。

Dkim-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samuraism.com; s=gmaildkim;

d=のドメインがGoogleとかZendeskとかのドメインになっている場合はfromアドレスのドメインの保有者が作成したメールとは判断できない「第三者認証」と呼ばれる物になる。改竄されていないことは検証できるが、ドメインを所有している人からのメールだとは検証できない状態。

総合的な確認

mail testerでは、送られたメールを検証して10点満点でスコアをつけてくれます。
トップページを開くと、先方が検証に使うための専用のメールアドレスを用意してくれているので、メールを送ります。
メール文面もスコアリングの対象なので、(個人情報をマスクなどした上で)実際にシステムから送られる文面を使いましょう。

メールを送ったら”Then check your score”を押すと、スコアをつけてくれます。DMARCはスコアの対象外ですが、SPFとDKIMIについては見てくれているようです。
何が問題でスコアが下がっているかも表示されます。改善を施した上で、同じメールアドレスに再送したら、再度スコアをつけて貰うことも出来ます。

BIMI

先のAuthentication-Resultsヘッダに”insufficient dmarc”という文字列があってドキッとさせますが、これはBrand Indicators for Message Identificationという、メール送信者のブランドロゴを表示させる、いわばメール版のfaviconみたいな仕組みの仕様を満たしていないよ、という意味です。
例えば楽天はグループ全体で対応させているようで、以下のようにメーラで確認ができます。分かりやすくていいですね!

default._bimiというDNSレコードで設定状況を確認できます:

 % dig default._bimi.rakuten.com TXT

; <<>> DiG 9.10.6 <<>> default._bimi.rakuten.com TXT
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 31023
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;default._bimi.rakuten.com.	IN	TXT

;; ANSWER SECTION:
default._bimi.rakuten.com. 21600 IN	TXT	"v=BIMI1; l=https://r.r10s.jp/com/bimi/r_crimsonred/r_crimsonred.svg;a=https://r.r10s.jp/com/bimi/r_crimsonred/r_crimsonred_177085657.pem;"

;; Query time: 39 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Fri Jan 19 13:34:12 JST 2024
;; MSG SIZE  rcvd: 204

Gmailでも表示させるには、VMCという仕組みを利用するために年間数十万の費用をかけて認証してもらう必要があるようです。
自分の会社で送るのはほぼトランザクションメールで、受信者は読む動機があるので今のところはいいかな、と思っています。
マーケティングメールを頻繁に送る組織ではお金をかけてBIMIに対応させるのもいいかもしれません。

The post Google WorkspaceやZendeskから送信されるメールが迷惑メールとならないようにする: SPF、DKIM、DMARCの設定の覚書 first appeared on yusuke.blog.]]>
3362
required属性で入力必須項目のチェックをブラウザに行わせる https://yusuke.blog/2022/04/17/3270 Sun, 17 Apr 2022 08:20:03 +0000 https://yusuke.blog/?p=3270 入力必須項目チェック、これまえJavaScriptで行っていました。調べたところ、HTML5でrequiredという属性…

続きを読む

The post required属性で入力必須項目のチェックをブラウザに行わせる first appeared on yusuke.blog.]]>
入力必須項目チェック、これまえJavaScriptで行っていました。調べたところ、HTML5でrequiredという属性が導入されていたようです。
required属性を書いておけばsubmit時、ブラウザが入力済みかどうかをチェックしてくれます。入力済みでなければ入力を促して送信は行われません。

type="email"のinputで、requiredの代わりにmultipleと記載しておくとメールアドレスをスペース区切りまたはカンマ区切りで複数指定してもらうことが可能です。
何も入力がない場合、または正しいメールアドレスが複数並んでいる場合にvalidと判定されます。CCメールアドレスを指定して貰う欄なんかは良いですね。requiredと合わせて指定することで「1つ以上」のメールアドレスを入力必須とすることも出来ます。

また、:invalid疑似クラスを使うことで必須項目が入力されていない際のスタイルを指定することもできます。

JavaScriptで.required=true/falseとすれば動的に入力必須/不要をトグルすることもできます。
ただし、HTML要素的には属性の存在の有無で入力の要/不要が決まるため、required=”false”と書いても入力不要にはなりません。
また、技術的に入力漏れを確実に防ぐものではありません。古いブラウザや、機械的な手段で入力が漏れる可能性はあるため、ロジック上必要な項目についてはサーバサイドでのチェックは引き続き必要です。

動作をざっと把握できるコードは以下のようになります。

<style>input:invalid{background-color:#ffebeb;}</style>
<form>
  <label for="name">名前</label><input type="text" id="name" name="name"/>
  <label for="email">メールアドレス</label><input type="email" id="email" name="email" required/>
  <label for="emailmulti">メールアドレス(複数)</label><input type="email" id="emailmulti" name="emailmulti" multiple/>
  <input type="submit" value="送信"/>
</form>

<button onclick="document.getElementById('name').required=true">名前を入力必須にする</button>

<button onclick="document.getElementById('name').required=false">名前を入力必須では無くする</button>

動作するサンプル:




The post required属性で入力必須項目のチェックをブラウザに行わせる first appeared on yusuke.blog.]]>
3270