2038年問題とは?-2000年問題の再来?2038年問題の影響と解決方法-

Share

Security NEWS TOPに戻る
バックナンバー TOPに戻る

本記事では最近話題の「2038年問題」について解説します。2038年問題は狭義のサイバーセキュリティと関連するものではありませんが、そのまま放置してしまうとサイバーインシデントを引き起こす可能性がある問題となります。対応に準備に時間を要する問題であることから、読者の皆さまに早い段階から関心を持っていただければと考えています。

2000年問題を振り返る

初期のプログラミング言語(FORTRANやCOBOL注 1) など)はデータ型に日付型がなかったため、文字列を割り当てて日付として処理をしていました。

この時、日付を文字列で処理する際、1960年代~80年代の人類は自分が作ったプログラムがその後長く使われるなどと思わず、「とりあえずYY-MM-DDで表示すればデータ量削減にもなるし、いいだろう」と考え、慣例として西暦年を下2桁で処理していました。

図1:2000年問題の原因となった表示方法

何しろ今とは異なりCPUもメモリも、貧弱でも超高価な時代です。資源の節約は必要な限り実行しなければならない課題だったといえます。しかし、1990年代に入ったところで人類はふと気づきます。「これはもしや、西暦年の下2桁だけだと2000年になった時、処理上1900年に戻ってしまうのでは?」と。

図2:2000年問題

そうして、1990年代半ばからプログラムの書き換えが行われ、それまで下2桁だった西暦年を4桁に変更し、万が一の時のために1999年12月31日から2000年1月2日までの間、一部のIT業界の人たちが正月返上で出勤して不測の事態に備えたのが2000年問題です。

2000年問題では実際、2000年1月1日当日、特に何かが起こることはありませんでした。その背景は以下の通りです。

2000年問題が2000年1月1日に何も問題とならなかった背景

  • COBOLやFORTRANなどのレガシー言語で古くに書かれたアプリケーションやマイコンなど対象が限定されていたこと
    (※C言語などの比較的新しい言語は日付型をデータ型に持っていたため関係がなかった。)
  • 発生日が明確だったこと
  • 対策が西暦年の2桁を4桁表示に変更するという方法に集約されていたこと
  • 数年間にわたって事前の対策がとられていたこと

限定的な対象に対し、事前に入念な準備を行ったことが功を奏し、インシデントが発生しなかったことが2000年問題の結果です。

計算機とデータ型:2038年問題の技術的背景

さて2024年現在、コンピューター・タブレット端末・スマートフォンなど、見た目などから計算機であることがわかりづらいようになっていますが、やはりコンピューターは計算機です。実際アプリケーションを動かすにしてもプログラムがされていて、プログラムの実行には必ず計算が伴います。そして、プログラム上でデータを処理するためにはデータの種類を定めるデータ型というものがあります。

データ型の例

データ型
文字列(str)今ご覧になっているいわゆる文字列のこと
整数型(int)1, 2, 50, 1065, -5などの整数(負の数も含む)
浮動小数点型(float)3.14, -0.001, 356.25などの小数点を含む数(負の数も含む)
ブーリアン型(bool)真(True)か偽(False)のいずれかで表わされる
日付型(date)世界標準時(UTC)を基準として、1970年1月1日からの経過秒数を表すタイムスタンプデータ。整数型データで表わされる

2000年問題のときはFORTRANやCOBOLに日付型が存在せず、文字型で処理していたこと、また限られた資源を節約するために下2桁で年を表していたことが原因でした。一方、2038年問題は日付型のタイムスタンプデータを格納する整数型のデータ長(ビット幅)の実装が原因となるものです。

SQAT.jpでは以下の記事で2024年版のプログラミング言語をめぐる状況と、ちょっとした脆弱性対策に関する情報をご紹介しています。こちらもあわせてご覧ください。
【続】プログラミング言語の脆弱性対策を考える:2024

2038年問題の技術的課題

符号付32ビット整数型から符号付64ビット整数型への移行の壁

前述したデータ型の例の表にもあるように日付型は絶対的な日付を表すものではなく、1970年1月1日午前0時0分を基準日時(エポックタイム)としてそこからの経過秒数をタイムスタンプデータとしてあらわすものです。C言語ではtime_tと呼ばれるこのデータでは、タイムスタンプデータを格納するのは符号付32bitの整数型となっています。符号付整数型は最初の1bitを正負符号のために使用します。符号の1ビットがあるため、実際に日付データ用に利用できるのは正負を表す最初の1ビットを除く31ビットで、利用できるビット長は(231-1)=2,147,483,647秒となります。よって基準日時からおよそ68年を上限として演算・表示ができるものとなります。

図3:符号付32bitであらわした2038年1月19日3時14分7秒

図3は1970年1月1日午前0時0分から2,147,483,647秒が経過した、2038年1月19日3時14分7秒(※うるう秒は考慮しておりません)の符号付32bit整数型でのtime_tの状態です。一番左側の符号0は正の値を表しており、1970年1月1日午前0時0分から2,147,483,647秒、正の方向に経過したことを示します。

さて、二進法の常で右側の31bitがすべて1になった場合、通常一番左側の1ビット目が1になります(二進法の繰り上がり)。

図4:符号付32bitのままで2038年1月19日3時14分8秒になった場合

1970年1月1日午前0時0分から2,147,483,648秒経過すると図4のようになります。符号付の場合、一番左側の符号1は負の値を表すため、1970年1月1日午前0時0分から2,147,483,647秒、負の方向に遡った1901年12月13日20時45分52秒を示します。つまり放置しておくと日付データが大きく誤ることとなります。この問題が最も深刻になるのは符号付32bitのtime_tを何らかの形で参照し、それを正しいものという前提で処理しているプログラムが、2038年1月19日の時点(または2038年1月19日以降の日付を参照する時点)で未改修のまま残ってしまうことで影響を及ぼしてしまうことなのです。

ウェビナー開催のお知らせ

  • 2024年12月18日(水)14:00~15:00
    脆弱性診断の新提案!スピード診断と短納期で解決する「SQAT® with Swift Delivery」セミナー
  • 最新情報はこちら


    2038年問題を回避する3つの対応策

    対策として考えられる方法はいくつかありますが、根本的な対策は以下の3つになります。

    1. time_tを符号付64bit整数型に変更する
    2. time_tを符号なし32bit整数型に変更する
    3. time_tの基準日時を1970年1月1日午前0時0分から別の日時に移動する

    主要OS・アプリケーションの2038年問題対応状況

    2038年問題の影響が一番大きく出ると当初予想されていたのが各種OSです。以下に各OSの対応状況を記載します。

    各OSの対応状況

    OS
    Linux64bitアーキテクチャ向けには当初より64bitのtime_tを提供。
    32bitアーキテクチャについてはLinux Kernel 5.6で64bit化対応済み。5.4/5.5についてもバックポートで対応済み。*1
    FreeBSD原則として64bit対応済みだが、i386アーキテクチャの32bitアーキテクチャのみ非対応。I386アーキテクチャについては符号なしの32bit整数型 time_tを提供*2
    Windows64bitで1601年1月1日0時からの100n sec単位の差分計算をしていることから2038年問題は対象外といわれている*3
    macOSmacOS10.0(Cheetah)で基準時を2001年1月1日0時に変更しており、2038年問題は対象外。また、32bitアプリケーションはmacOS 10.15(Catalina)以降では使用できない*4

    表にもある通り、最新のOSであればほぼ問題なく2038年問題をクリアできることがわかります。問題はOSの機能を補完する各種ドライバやライブラリ群、また、そのうえで動くアプリケーションでしょう。それぞれ確認は必要となりますが、代表的なものの対応状況は以下の通りです。

    ライブラリ/アプリケーション名対応状況
    GNU C Library (glibc)バージョン2.34でx86アーキテクチャ上での64bit整数型time-tに対応。ただしx86アーキテクチャ上のglibcのtime_t自体は32bitのままで、_TIME_BITSプリプロセッサマクロが64に設定されていて、かつLFSが有効な場合にのみ利用可能などの制限あり*5
    NFSNFSv4(RFC7530)秒単位のデータは符号付64bitであることが定義されている*6(※2.2.1 nfstime4の項を参照)
    XFSLinux 5.10でオプションとしてナノ秒単位を64bitで計算・表示する「big timestamps」を追加し、2486年まで対応できるように修正。ただしデフォルトで追加が反映されるものではなく有効に設定する必要がある*7
    MySQL8.0.28でFROM_UNIXTIME(), UNIX_TIMESTAMP(), CONVERT_TZ() の64bit対応。ただしOS側が64bit対応である必要あり(いずれの関数もOSの日付型データを参照するため)*8
    MariaDB11.5.1でタイムスタンプを2106年02月07日6時28分15秒まで拡張*9
    Visual C++32bitであえて指定されていない限りは64bitがデフォルト値*10

    上記はごく一部の対応状況ですが、仮に対応していても制限事項がつくものが存在する点に注意が必要です。ここまで記載した内容で何となくお気づきの方もいらっしゃるかもしれませんが、2038年問題は発生する可能性がある箇所が2020年問題に対して格段に多いため、時間がかかることが予想されます。

    2000年問題と2038年問題の違い

    • 対象がOS/ライブラリからアプリケーション、機器類まで非常に幅が広い
    • 2000年当時に比べて格段にデジタル化が進んでいる
    • 対策方法が一様ではないものや、現在動いているシステムに対して即時変更をかけられないものがある

    企業が取るべき2038年問題対策:自社システムの診断方法

    自社のプログラムの調査は?

    さて、「PCやサーバなんかを買ってきたものの、自社で作ったものはどうすればいいの?」というケースもあるでしょう。自社で作ったものは…そうです。自分たちで調べるしかないのです。実際に調査をして対応をした事例がまとめられた論文が公開されています。

    組込み機器開発における2038年問題への対応事例

    https://www.ipsj.or.jp/dp/contents/publication/39/S1003-1809.html

    この事例では製品のライフサイクルがもともと20年前後を想定していることから、まずは2038年を最低限クリアすることを要件として調査を開始しています。このケースは組み込み機器になりますが、その単体の機器でもOS部分を含む総行数330万行のコードから符号付32bit整数型のtime_tを明示的に使用する箇所およそ3500か所が発見されています。

    この事例でとられたステップを簡単にまとめます。

    この事例では3500か所に対して5.8人月で実行された修正作業もさることながら、そのレベルの工数で抑制するために事前の洗い出しや対策案の立案、修正作業の手順策定といったところの重要さが感じられます。特に対策案を選定するにあたって要件が明確だったことが対策案の選定を容易にしたことがわかることから、作業開始前(せめて対策案の選定前)に要件を明確にしておくことの重要さを実感させられます。

    さて、2038年問題に該当するコードを検出するためのツールは日本の研究者も含め、いくつかのGitHubレポジトリからリリースされています。最近では立命館大学のサイバーセキュリティ研究室によるY2k38チェッカーがリリースされています。

    Y2k38チェッカーチェッカー作者によるプレゼン資料

    こういったチェッカーは自社開発のプログラム資産のざっとしたチェックに使えるでしょう。また、チェッカー以前の問題として、まずは自社のプログラム資産が2038年問題の影響を受けないか、そろそろ確認を行い、準備を始める期間に入ってきたといえるかもしれません。

    組み込み機器とは?:2038年問題の最大の影響

    実はここまでにあまり触れていない、最大の2038年問題があります。それは、先ほどの論文の事例にもある組み込み機器の問題です。

    組み込み機器といわれてもピンとこない方もいらっしゃるかもしれません。身近な例でいうと家電製品を制御するために組み込まれているコンピューターになります。一番パソコンに近いものであれば最近のハードディスク内蔵か外付け対応のテレビが挙げられます。このほかにも例えば電車に乗るときの自動改札機、切符販売機、水道や電気ガスなどのメーター類や街中で見かけるデジタルサイネージなども組み込み機器です。ほかにも工場のセンサー類やオートメーション用の機器類、配電設備や浄水・配水設備などのインフラ設備、病院の検査機器などにも組み込み機器が用いられています。

    先ほどの事例のようにライフサイクルが決まっていて、そのライフサイクルの間のみ使用するというのが利用者(消費者)側に正しく認識されていれば問題ないのですが、実際のところ、組み込み機器こそライフサイクルを超えて、転売などをされて使い続けられるケースが多く、販売業者も製造業者もすべての出荷品の現状をトレースできないケースがあるといわれています。特に償却期間が5年を超えるような固定資産については入れ替えの検討なども含めて対応する必要が出てくることから、そろそろ取りまとめを始めなければならないでしょう。また、個人向けのIoT機器や家電のように、長期間の利用は想定されていない(売り切りに近い)製品については直前になって買い替えが必要といったアナウンスが出てくる可能性もあるでしょう。

    サイバーインシデント緊急対応

    サイバーセキュリティ緊急対応電話受付ボタン
    SQAT緊急対応バナー

    まとめ

    2038年問題は日付データが誤ることで社会的に大きな影響を与える可能性があります。本記事公開日(2024年12月)時点ではまだまだ先の問題と思っている方が多いと思いますが、そろそろロードマップを書き始めないと対策に取る時間が足りなくなる可能性があります。これを念頭に置き、早めの対策方法を考えておく必要があるでしょう。


    Security NEWS TOPに戻る
    バックナンバー TOPに戻る

    注:
    1)FORTRAN
    ・数学分析用を目的としたプログラミング言語
    ・データ型は整数、実数、複素数、文字、論理の5種類
     COBOL
    ・1950年代終わりに開発されたプログラミング言語
    ・データ型は文字、数字、数字編集の3種類


    資料ダウンロードボタン
    年二回発行されるセキュリティトレンドの詳細レポート。BBSecで行われた診断の統計データも掲載。
    お問い合わせボタン
    サービスに関する疑問や質問はこちらからお気軽にお問合せください。

    Security Serviceへのリンクバナー画像
    BBsecコーポレートサイトへのリンクバナー画像
    セキュリティ緊急対応のバナー画像

    プログラミング言語の脆弱性対策を考える

    Share

    Security NEWS TOPに戻る
    バックナンバー TOPに戻る

    プログラミング言語のセキュリティは、組織のシステム全体のセキュリティに大きな影響を与えます。「アプリケーションの脆弱性の半数はC/C++に起因する」という報告もあり、プログラミング言語における脆弱性の特徴を理解し、適切な対策を講じることは、いまや組織のセキュリティに不可欠な取り組みといえます。本記事では、プログラミング言語の最新動向、脆弱性が生まれる背景を解説します。

    プログラミング言語のトレンド

    言語 使用している
    開発者の比率
    JavaScript69.7%
    HTML/CSS 62.4%
    SQL 56.9%
    Python 41.6%
    Java 38.4%
    Bash/Shell/PowerShell 34.8%
    C# 32.3%
    TypeScript 28.3%
    PHP 25.8%
    C++20.5%
    C 18.2%
    Go 9.4%
    Kotlin8.0%
    言語 使用している
    開発者の比率
    Ruby7.5%
    VBA6.2%
    Swift6.1%
    R5.5%
    Assembly4.9%
    Rust4.8%
    Objective-C4.4%
    Scala3.9%
    Dart3.7%
    Perl3.3%
    Haskell1.8%
    Julia0.9%

    Stack Overflow Developer Survey 2020 より弊社作成
    https://insights.stackoverflow.com/survey/2020#technology-programming-scripting-and-markup-languages-professional-developers

    JavaScript、HTML/CSS、SQLなどが上位に並んでいますが、皆さんの予想どおりでしょうか?ちなみに冒頭で述べた、「脆弱性の半数」を生み出すとされるC/C++に関しては、昨今IoTデバイスなどの組込機器やデスクトップアプリケーション等に利用目的が収れんしてきているといわれ、その使用率は減少傾向にあります。また、リストには記載がありませんが、日本に限ってみると、COBOLなどのレガシーシステム向けの言語がいまだ根強いシェアを保っているのはご存じの方も多いことでしょう。

    なお、弊社での診断傾向としては、JavaScriptのほか、Pythonが目立っています。今後については、「オーバーヘッドが少なく、静的型付け言語である」という特徴をもつTypeScriptなどが、軽量さの望まれるサーバレス環境での需要につながるものとみられます。また、Android端末向けにKotlinの需要も高まると予測しています。以下、ご参考に、プログラミング言語と主な利用分野のマッピングを示します。

    図:主要プログラミング言語と現在利用されている代表的分野

    プログラミング言語の脆弱性 ― 言語ごとに異なる特徴を知る

    プログラミング言語の脆弱性を考える場合、特定の言語に固有のものと、言語間で共通のものを押さえておく必要があります。

    例えば、C/C++では、その脆弱性の7割がメモリハンドリングのミスに起因するといわれており、メモリ関連処理のロジックを正しく制御させ、ソースコード内に脆弱性を作りこまないようにすることが、重要なセキュリティ対策となります。そのほか、言語固有の脆弱性として代表的なものは、Javaでの「安全でない入力に対するデシリアライゼーション」の問題、JavaScriptでの「パストラバーサル」や「暗号」の問題、PHPでの「クロスサイトスクリプティング(XSS)」や「SQLインジェクション」などになります。

    なお、2000年代後半以降にリリース開始された比較的新しいプログラミング言語(Kotlin、Golang、Rustなど)については、上記とは若干が異なる観点からの注意が必要です。まず、こうした言語では、セキュアコーディングのための様々な関数やライブラリなどが用意され、セキュリティに関する手厚い対策が組み込まれているのですが、その一方で、セキュリティの機能が増えれば増えるほど関連ドキュメントが膨大になり、把握が追いつかないという課題が生じています。例えば、Kotlinの場合、Kotlin自体のドキュメンテーションではセキュリティ関連の記述はNULLの安全性に触れる程度なのですが、セキュアコーディングに取り組もうとすると、膨大なAndroid Developer Guideを参照する必要があります。また、相互運用性への配慮も必要です。例えばKotlinやGolangはJavaと一緒に利用するケースが多いため、こうした言語で開発を行う場合には、Java側の環境を考慮したうえでのセキュアコーディングが不可欠になり、それが開発の難易度を押し上げているという状況があります。

    プログラミング言語の脆弱性 ― 全言語に共通の特徴を知る

    続いては、すべての言語に共通する脆弱性です。これは大きく以下の3つに分類できます。

    情報漏洩
    ・表示する必要のない機微な情報(ユーザ名やIDなど)の露呈
    ・不要なシステム情報の公開
    入力検証の不備
    ・不正なパラメータの許容、XSS、SQLインジェクション
    ・HTTPヘッダ分割
    認可・認証関連の脆弱性
    ・オブジェクトやファイルなどへのアクセス認可の不備
    ・認証情報の保護機構や暗号化の不備

    脆弱性が発生する背景

    以上述べてきたような脆弱性は、なぜ発生するのでしょう。その背景には、開発現場における以下のような課題があると考えられます。

    ・プロジェクトベースで人員が変わることが多く、知識や経験の共有が行われることがまれ
    ・脆弱性やセキュアコーディングに対する意識、知識レベルがプログラマによって異なる
    ・ギリギリのスケジュールでプロジェクトが進むことが多く、知識や経験の共有まで手が回らない
    ・セキュリティへの対応が明示的な業務として遂行されるのではなく、プログラマやプロジェクトメンバー1人1人の善意に依存する面が強い

    具体例で説明しましょう。先ほど、PHPではXSSやSQLインジェクション等の脆弱性がよく見られると述べました。しかし、PHPでも、バージョン4以降であれば「htmlspecialcharacters」という関数を利用することでXSSの回避に必要な特殊文字のエスケープ処理ができます。SQLインジェクションについても、プレースホルダの利用による回避が可能です。このように、すでに対策が存在する場合であっても、プログラマ間で知識や経験の共有が行われていない場合、ソースコード診断やステージング環境でのWebアプリケーション脆弱性診断が実施されない限り、脆弱性は放置されることになります。また、「機微な情報の露呈」という問題については、個人情報保護などの法制度に対する知識が共有されておらず、そもそも課題として認識されていないという可能性があります。なお、知識共有のハードルは、セキュリティ機能が充実しているゆえに把握すべき情報量が膨大で、他の言語との互換性等まで含めた配慮が求められる最近のプログラミング言語では、さらに高いといえるでしょう。

    こうした課題を解決するには、プログラマ個人の知識・技術レベルを高めることはもちろんですが、それ以上に重要なのは、組織を挙げての体系的な取り組みであるといえます。

    先手を打った対処がカギ

    そこでぜひ取り入れたいのが、プログラミング言語に関わる脆弱性が生じていないかを、開発の初期段階から継続的に点検する取り組みです。これは「DevSecOps」とも呼ばれる考え方で、「開発(Dev)」・「運用(Ops)」に「セキュリティ(Sec)」の観点を組み込むことで、システムのセキュリティ強化を図るものです。開発プロジェクトは常に時間との闘いですが、だからといって脆弱性への対応を先送りしてはなりません。対処が事後になればなるほど、影響範囲が広がり、コストも肥大する恐れがあります。

    以前の記事でも解説しましたが、何よりも、初期段階からの取り組みが重要です。例えば、人員の流動が激しいプロジェクトベースの現場では、開発の早期からソースコード診断を含むテスト活動を実施し、脆弱性をコード単位で効率的に解消していくことによって、各段階で積み上げられた知識や経験を、後続の工程で活用することが可能になります。また、近年主流になっているアジャイル型の開発手法でもこれは有効で、短い開発サイクルが繰り返される中で早期に・こまめにテストや修正を行うようにすることで、セキュリティを強化できるのみならず、プロジェクト全体の工数も抑制できます。なお、短いサイクルでテストを回すには、SaaSタイプのソースコード診断サービスの利用を検討してもよいでしょう。

    先手を打って脆弱性に対処できれば、脆弱性の要因となっていた様々な課題に取り組む余裕も生まれます。結果として、セキュリティと開発効率をともに高められる好循環を実現できるのではないでしょうか。

    Security NEWS TOPに戻る
    バックナンバー TOPに戻る


    資料ダウンロードボタン
    年二回発行されるセキュリティトレンドの詳細レポート。BBSecで行われた診断の統計データも掲載。
    お問い合わせボタン
    サービスに関する疑問や質問はこちらからお気軽にお問合せください。

    Security Serviceへのリンクバナー画像
    BBsecコーポレートサイトへのリンクバナー画像
    セキュリティ緊急対応のバナー画像
    セキュリティトピックス動画申し込みページリンクへのバナー画像