読み込み中...

JavaScriptのoriginとは?応用例まで理解する完全ガイド8選

JavaScriptのoriginを表す図解 JS
この記事は約19分で読めます。

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

本記事のサンプルコードを活用して機能追加、目的を達成できるように作ってありますので、是非ご活用ください。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を満たす現役のプログラマチームによって監修されています。

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

●originとは?

JavaScriptを使ってWebアプリケーションを開発していると、「origin」という言葉をよく耳にしますよね。

でも、originって具体的に何を指しているのでしょうか?

ちょっとややこしいですが、originを正しく理解することは、セキュリティの観点からとても重要なんです。

そもそもoriginとは、URLを構成する要素の一部で、スキーム、ホスト名、ポート番号を組み合わせたものを指します。

例えば、https://www.example.com:443というURLの場合、originはhttps://www.example.com:443になります。

つまり、originはURLのうち、パスやクエリパラメータを除いた部分ということですね。

○originの構成要素

originを構成する要素をもう少し詳しく見ていきましょう。

  1. スキーム:HTTPやHTTPSなどのプロトコルを指定します。
  2. ホスト名:ドメイン名やIPアドレスを指定します。
  3. ポート番号:通信に使用するポート番号を指定します(HTTPは80、HTTPSは443が標準)。

これらの3つの要素を組み合わせたものがoriginなんです。

ちなみに、ポート番号が標準のものである場合は、originを表示する際に省略されることもあります。

○originの具体例

具体的なoriginの例を見てみましょう。

  • https://www.example.com(ポート番号は省略)
  • http://localhost:8080
  • https://192.168.0.1:443

このように、スキーム、ホスト名、ポート番号の組み合わせがoriginになります。

○サンプルコード1:URLからoriginを取得

実際にJavaScriptでoriginを取得するには、window.location.originを使います。

const url = 'https://www.example.com:443/path/to/page?query=string';
const origin = new URL(url).origin;
console.log(origin); // 出力: https://www.example.com:443

このコードでは、まずURLを文字列として定義し、URLコンストラクタを使ってURLオブジェクトを作成しています。

そして、originプロパティを使ってoriginを取得しています。

実行結果からわかるように、originはスキーム、ホスト名、ポート番号の組み合わせになっています。

パスやクエリパラメータは含まれていませんね。

●originの重要性

originを理解することは、Webアプリケーションのセキュリティを考える上で非常に重要です。

特に、JavaScriptを使って開発する際は、originの概念を正しく理解していないと、思わぬセキュリティホールを作ってしまうかもしれません。

では、なぜoriginがそんなに重要なのでしょうか?

その理由は、Webブラウザがセキュリティ上の制約として「同一オリジンポリシー」を採用しているからなんです。

聞き慣れない言葉かもしれませんが、これからしっかり説明していきますので、一緒に理解を深めていきましょう。

○同一オリジンポリシー

同一オリジンポリシーとは、あるオリジンから読み込まれたスクリプトが、別のオリジンのリソースにアクセスすることを制限するセキュリティ機構のことです。

つまり、あるWebサイトから読み込まれたJavaScriptは、原則として同じオリジン内のリソースしかアクセスできないということですね。

どうしてこのような制限があるのでしょうか?

それは、悪意のあるスクリプトが別のサイトの情報を勝手に読み取ったり、操作したりすることを防ぐためです。

もし同一オリジンポリシーがなかったら、例えば、あなたがログインしているWebサイトの情報を、別のサイトのスクリプトが勝手に読み取ることができてしまうかもしれません。

これでは、安心してWebサイトを利用できませんよね。

○CORS(Cross-Origin Resource Sharing)

しかし、同一オリジンポリシーがあるからといって、別のオリジンのリソースに一切アクセスできないわけではありません。

そこで登場するのが、CORS(Cross-Origin Resource Sharing)という仕組みです。

CORSは、サーバー側で特定のオリジンからのアクセスを許可することで、同一オリジンポリシーの制約を緩和する方法です。

つまり、サーバー側で「このオリジンからのアクセスは許可するよ」と設定しておけば、クライアント側のJavaScriptは、別のオリジンのリソースにアクセスできるようになるんです。

ただし、CORSの設定を誤ると、意図しないオリジンからのアクセスを許可してしまう可能性があるので、注意が必要です。

○サンプルコード2:CORSエラーの再現と対処法

CORSが正しく設定されていない場合、クライアント側のJavaScriptは別のオリジンのリソースにアクセスしようとしてエラーになります。

では、実際にCORSエラーを再現し、その対処法を見ていきましょう。

まず、http://localhost:3000で提供されているWebアプリケーションがあり、そこからhttp://localhost:4000で提供されているAPIにアクセスしようとしているとします。

// http://localhost:3000 のスクリプト
fetch('http://localhost:4000/api/data')
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error('Error:', error));

このスクリプトを実行すると、次のようなエラーが発生します。

Access to fetch at 'http://localhost:4000/api/data' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

これは、http://localhost:4000のサーバーがhttp://localhost:3000からのアクセスを許可していないために発生するCORSエラーです。

この問題を解決するには、http://localhost:4000のサーバー側で、http://localhost:3000からのアクセスを許可する設定を行う必要があります。

Node.jsのExpressを使った例を見てみましょう。

const express = require('express');
const app = express();

app.use((req, res, next) => {
  res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000');
  next();
});

app.get('/api/data', (req, res) => {
  res.json({ message: 'Hello, CORS!' });
});

app.listen(4000, () => {
  console.log('Server is running on port 4000');
});

このコードでは、Access-Control-Allow-Originヘッダーを設定することで、http://localhost:3000からのアクセスを許可しています。

これで、先ほどのクライアント側のスクリプトを実行すると、CORSエラーが発生せずに、APIからデータを取得できるようになります。

{
  "message": "Hello, CORS!"
}

このように、originとCORSの概念を理解することで、セキュリティを考慮しつつ、必要に応じて別のオリジンのリソースにアクセスできるようになります。

●originの取得方法

originの重要性やCORSについて理解が深まってきたところで、実際にJavaScriptでoriginを取得する方法を見ていきましょう。

ここからは、コードを交えながら、originの取得方法を具体的に説明していきます。

○window.location.origin

originを取得する最も簡単な方法は、window.location.originを使うことです。

これは、現在のページのoriginを文字列で返してくれるプロパティなんです。

console.log(window.location.origin);
// 出力例: https://example.com

このコードを実行すると、現在のページのoriginが出力されます。

とてもシンプルですね。

ただし、window.location.originは比較的新しいプロパティで、古いブラウザではサポートされていない場合があります。

そのような場合は、別の方法を使う必要があります。

○URL()コンストラクタ

もう一つの方法は、URL()コンストラクタを使うことです。

これは、URLを解析するための標準的な方法で、originを取得することもできます。

const url = new URL(window.location.href);
console.log(url.origin);
// 出力例: https://example.com

このコードでは、まずwindow.location.hrefから現在のページのURLを取得し、URL()コンストラクタに渡しています。

これによって、URLオブジェクトが作成されます。

そして、そのオブジェクトのoriginプロパティを使って、originを取得しているんです。

○サンプルコード3:originの様々な取得方法

では、実際にoriginを取得するための様々な方法を試してみましょう。

// 方法1: window.location.origin
console.log('方法1:', window.location.origin);

// 方法2: URL()コンストラクタ
const url = new URL(window.location.href);
console.log('方法2:', url.origin);

// 方法3: window.locationのプロパティを組み合わせる
console.log('方法3:', window.location.protocol + '//' + window.location.host);

// 方法4: a要素を使う
const a = document.createElement('a');
a.href = window.location.href;
console.log('方法4:', a.protocol + '//' + a.host);

実行結果

方法1: https://example.com
方法2: https://example.com
方法3: https://example.com
方法4: https://example.com

方法1と方法2は、先ほど説明した通りです。

方法3は、window.locationprotocolhostプロパティを組み合わせてoriginを取得しています。

方法4は、一旦a要素を作成し、そこに現在のURLを設定することで、protocolhostプロパティからoriginを取得しています。

どの方法を使うかは、ブラウザのサポート状況や好みに応じて選択すると良いでしょう。

○ホスト名のみの取得

originは、プロトコル、ホスト名、ポート番号の組み合わせですが、時にはホスト名だけを取得したいこともあるでしょう。

○サンプルコード4:ホスト名の取得

ホスト名だけを取得するには、window.location.hostnameを使います。

console.log(window.location.hostname);
// 出力例: example.com

このコードを実行すると、現在のページのホスト名が出力されます。

ポート番号は含まれていないので、注意してくださいね。

●originに関するよくあるエラーと対処法

JavaScriptでoriginを扱っていると、時々厄介なエラーに遭遇することがあります。

でも、大丈夫です。

ここでは、originに関連するよくあるエラーとその対処法を見ていきましょう。

エラーメッセージを理解し、適切に対処できるようになれば、Webアプリケーション開発の幅が広がること間違いなしです。

○”Origin null is not allowed by Access-Control-Allow-Origin”

まず、「”Origin null is not allowed by Access-Control-Allow-Origin”」というエラーメッセージを目にしたことがある方も多いのではないでしょうか。

このエラーは、通常、ローカルファイルからJavaScriptを実行した際に発生します。

エラーの原因は、ブラウザのセキュリティ制限によるものです。

ローカルファイルから実行されたJavaScriptは、originが「null」になるんです。

そして、多くのサーバーは、「null」originからのリクエストを許可していません。

この問題を解決するには、ローカルサーバーを立ち上げて、JavaScriptをそこから実行するのが一般的です。

例えば、Node.jsの「http-server」モジュールを使えば、簡単にローカルサーバーを立ち上げることができます。

# http-serverのインストール
npm install -g http-server

# ローカルサーバーの起動
http-server

これで、http://localhost:8080のようなURLからJavaScriptを実行できるようになります。

originが「null」ではなくなるので、エラーが解消されるはずです。

○オリジン間リソース共有ブロック

もう一つのよくあるエラーが、「オリジン間リソース共有ブロック」です。

これは、あるオリジンのJavaScriptが、別のオリジンのリソースにアクセスしようとした際に発生します。

先ほども説明したように、同一オリジンポリシーによって、JavaScriptは原則として同じオリジン内のリソースしかアクセスできません。

別のオリジンのリソースにアクセスするには、サーバー側でCORSの設定を行う必要があるのでした。

このエラーを解決するには、サーバー側で適切なCORSの設定を行うことが重要です。

具体的には、Access-Control-Allow-Originヘッダーを設定して、許可するオリジンを指定します。

app.use((req, res, next) => {
  res.setHeader('Access-Control-Allow-Origin', 'http://example.com');
  next();
});

上記の例では、http://example.comからのアクセスを許可しています。

必要に応じて、許可するオリジンを追加したり、*を指定してすべてのオリジンからのアクセスを許可したりすることもできます。

○リクエストヘッダのOrigin欄が空

最後に、リクエストヘッダのOrigin欄が空になってしまうケースを見てみましょう。

これは、リクエストを送信するJavaScriptコードが、Originヘッダーを設定していない場合に発生します。

fetch('http://example.com/api', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(data)
});

上記のコードでは、headersオブジェクトにOriginヘッダーが含まれていません。

その結果、サーバー側ではOriginヘッダーが空と判断され、エラーが発生する可能性があります。

この問題を解決するには、headersオブジェクトにOriginヘッダーを明示的に設定します。

fetch('http://example.com/api', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Origin': 'http://example.com'
  },
  body: JSON.stringify(data)
});

こうすることで、サーバー側でOriginヘッダーが正しく認識され、エラーを回避できます。

●originの実践的な使用例

ここまで、originの基本的な概念や取得方法、エラー対処法などを解説してきました。

でも、実際の開発現場では、originをどのように活用すればいいのでしょうか?

ここからは、originを使った実践的なコーディング例を見ていきましょう。

originを正しく理解し、適切に使いこなすことで、より安全で効率的なWebアプリケーション開発ができるはずです。

実際のコードを通して、originの活用方法を身につけていきましょう。

○サンプルコード5:別オリジンへのデータ送信

まず、別のオリジンへデータを送信する例を見てみましょう。

ここでは、http://example.comからhttp://api.example.comにデータを送信するケースを考えます。

const data = {
  name: 'John Doe',
  age: 30
};

fetch('http://api.example.com/user', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Origin': 'http://example.com'
  },
  body: JSON.stringify(data)
})
  .then(response => response.json())
  .then(result => {
    console.log('Success:', result);
  })
  .catch(error => {
    console.error('Error:', error);
  });

このコードでは、fetch関数を使ってhttp://api.example.com/userにPOSTリクエストを送信しています。

headersオブジェクトにOriginヘッダーを設定することで、リクエスト元のオリジンを明示的に指定しています。

サーバー側では、Originヘッダーの値を確認し、許可されたオリジンからのリクエストであれば、適切なレスポンスを返します。

許可されていないオリジンからのリクエストであれば、エラーを返すことができます。

○サンプルコード6:条件付きリダイレクト

次に、originを使った条件付きリダイレクトの例を見てみましょう。

ここでは、ユーザーのオリジンに応じて、異なるページにリダイレクトするケースを考えます。

const allowedOrigins = [
  'http://example.com',
  'http://www.example.com',
  'https://example.com'
];

function redirectBasedOnOrigin() {
  const currentOrigin = window.location.origin;

  if (allowedOrigins.includes(currentOrigin)) {
    window.location.href = '/home';
  } else {
    window.location.href = '/access-denied';
  }
}

redirectBasedOnOrigin();

このコードでは、allowedOrigins配列に許可するオリジンを定義しています。

redirectBasedOnOrigin関数内で、window.location.originを使って現在のオリジンを取得し、allowedOriginsに含まれているかどうかを確認します。

許可されたオリジンであれば、/homeにリダイレクトします。

許可されていないオリジンであれば、/access-deniedにリダイレクトします。

このように、originを使って条件付きのリダイレクトを実装することで、アクセス制御を行うことができます。

○サンプルコード7:originを使った認証の例

originを使って、簡単な認証機能を実装してみましょう。

ここでは、特定のオリジンからのリクエストのみを許可するケースを考えます。

function authenticateOrigin(req, res, next) {
  const allowedOrigin = 'http://example.com';

  if (req.headers.origin === allowedOrigin) {
    next();
  } else {
    res.status(403).json({ error: 'Access denied' });
  }
}

app.get('/api/data', authenticateOrigin, (req, res) => {
  res.json({ message: 'Access granted' });
});

このコードでは、authenticateOriginミドルウェア関数を定義しています。

この関数は、リクエストヘッダのoriginallowedOriginと一致するかどうかを確認します。

一致する場合は、next()を呼び出して次のミドルウェアまたはルートハンドラに制御を渡します。

一致しない場合は、403ステータスコードとエラーメッセージを返します。

/api/dataルートでは、authenticateOriginミドルウェアを使って、アクセス制御を行っています。

許可されたオリジンからのリクエストのみが、{ message: 'Access granted' }というレスポンスを受け取ることができます。

○サンプルコード8:動的originの取得と利用

最後に、動的にoriginを取得し、利用する例を見てみましょう。

ここでは、ユーザーが現在閲覧しているページのoriginを取得し、それを使ってAPIリクエストを送信するケースを考えます。

function getUserData() {
  const currentOrigin = window.location.origin;

  fetch(`${currentOrigin}/api/user`, {
    method: 'GET',
    headers: {
      'Content-Type': 'application/json',
      'Origin': currentOrigin
    }
  })
    .then(response => response.json())
    .then(data => {
      console.log('User data:', data);
    })
    .catch(error => {
      console.error('Error:', error);
    });
}

getUserData();

このコードでは、window.location.originを使って現在のページのoriginを取得し、currentOrigin変数に格納しています。

getUserData関数内で、fetch関数を使って${currentOrigin}/api/userにGETリクエストを送信しています。

headersオブジェクトには、OriginヘッダーにcurrentOriginの値を設定しています。

サーバー側では、Originヘッダーの値を確認し、適切な処理を行うことができます。

まとめ

JavaScriptのoriginは、URLを構成する重要な要素で、同一オリジンポリシーやCORSに深く関わっています。

originを正しく理解し、適切に取得・操作することは、安全で信頼性の高いWebアプリケーション開発に欠かせません。

エラーに遭遇した際は、原因を究明し、適切な対処法を実践することが大切です。

originを活用した実践的なユースケースを通して、セキュリティを意識した開発を心がけましょう。

これからも、originを含めたセキュリティの知識を深め、ユーザーに信頼されるアプリケーションを開発していきましょう。