概要

サービスをインスツルメンテーションし、ユーザーのアクティビティを追跡することで、悪質なユーザーを検出・ブロックします。

Add authenticated user information on traces to identify and block bad actors targeting your authenticated attack surface. To do this, set the user ID tag on the running APM trace, providing the necessary instrumentation for ASM to block authenticated attackers. This allows ASM to associate attacks and business logic events to users.

Track user logins and activity to detect account takeovers and business logic abuse with out-of-the-box detection rules, and to ultimately block attackers.

ユーザーアクティビティの自動検出: Datadog トレーシングライブラリは、ユーザーアクティビティイベントを自動的に検出してレポートしようとします。詳細については、ユーザーアクティビティイベントの自動追跡を無効にするを参照してください。

すぐに使える検出ルールとして、以下のようなカスタムユーザーアクティビティがあります。

内蔵のイベント名必要なメタデータ関連ルール
activity.sensitive{ "name": "coupon_use", "required_role": "user" }IP からのレート制限アクティビティ
不正なアクティビティの検出
users.login.successユーザー ID は必須で、オプションでメタデータを追加できますCredential Stuffing attack
Bruteforce attack
Distributed Credential Stuffing
users.login.failureUser ID and usr.exists are mandatory, optional metadata can be addedCredential Stuffing attack
Bruteforce attack
Distributed Credential Stuffing
users.signup{ "usr.id": "12345" }IP からの過剰なアカウント作成
users.delete{ "usr.id": "12345" }IP からの過剰なアカウント削除
users.password_reset{ "usr.id": "12345", "exists": true }パスワードリセットのブルートフォース試行
payment.failureなしIP からの過剰な支払い失敗

認証されたユーザー情報をトレースに追加し、ユーザーブロック機能を有効にする

ルートスパンにカスタムタグを追加する方法と、後述のインスツルメンテーション関数を利用する方法があります。

ルートスパンにカスタムタグを追加するための Java トレーサーの API を使用し、アプリケーションで認証されたリクエストを監視できるように、ユーザー情報を追加します。

ユーザーモニタリングタグは、ルートスパンに適用され、プレフィックス usr の後にフィールド名が続きます。例えば、usr.name は、ユーザーの名前を追跡するユーザーモニタリングタグです。

: アプリケーションに必要な依存関係が追加されていることを確認してください。

以下の例では、ルートスパンを取得し、関連するユーザー監視タグを追加し、ユーザーブロック機能を有効にする方法を示しています。

import io.opentracing.Span;
import io.opentracing.util.GlobalTracer;
import datadog.appsec.api.blocking.Blocking;
import datadog.trace.api.interceptor.MutableSpan;

// アクティブスパンの取得
final Span span = GlobalTracer.get().activeSpan();
if ((span instanceof MutableSpan)) {
   MutableSpan localRootSpan = ((MutableSpan) span).getLocalRootSpan();
   // 必須ユーザー ID タグの設定
   localRootSpan.setTag("usr.id", "d131dd02c56eec4");
   // オプションのユーザーモニタリングタグの設定
   localRootSpan.setTag("usr.name", "Jean Example");
   localRootSpan.setTag("usr.email", "jean.example@example.com");
   localRootSpan.setTag("usr.session_id", "987654321");
   localRootSpan.setTag("usr.role", "admin");
   localRootSpan.setTag("usr.scope", "read:message, write:files");
}

Blocking
    .forUser("d131dd02c56eec4")
    .blockIfMatch();

.NET トレーサーパッケージは SetUser() 関数を提供し、トレースにユーザー情報を追加することで認証されたリクエストを監視できるようにします。

以下の例では、関連するユーザー監視タグを追加し、ユーザーブロック機能を有効にする方法を示しています。


using Datadog.Trace;

// ...

    var userDetails = new UserDetails()
    {
        // ユーザーに対するシステム内部識別子
        Id = "d41452f2-483d-4082-8728-171a3570e930",
        // ユーザーのメールアドレス
        Email = "test@adventure-works.com",
        // システムによって表示されるユーザー名
        Name = "Jane Doh",
        // ユーザーのセッション ID
        SessionId = "d0632156-132b-4baa-95b2-a492c5f9cb16",
        // ユーザーがリクエストしたロール
        Role = "standard",
    };
    Tracer.Instance.ActiveScope?.Span.SetUser(userDetails);

情報およびオプションについては、.NET トレーサーのドキュメントをお読みください。

Go トレーサーパッケージは SetUser() 関数を提供し、トレースにユーザー情報を追加することで認証されたリクエストを監視できるようにします。他のオプションについては、Go トレーサーのドキュメントをご覧ください。

この例では、現在のトレーサースパンを取得し、それを使用してユーザー監視タグを設定し、ユーザーブロック機能を有効にする方法を説明します。

import "gopkg.in/DataDog/dd-trace-go.v1/appsec"
func handler(w http.ResponseWriter, r *http.Request) {
  if appsec.SetUser(r.Context(), "my-uid") != nil {
    // 早急にリクエストハンドラーを中止して、ユーザーをブロックする必要があります。
    // ブロック応答は、appsec ミドルウェアによって自動的に処理され、送信されます。
    return 
  }
}

以下の API のいずれかを使用して、トレースにユーザー情報を追加し、アプリケーションで認証されたリクエストを監視できるようにします。

ddtrace 1.1.0 からは、Datadog::Kit::Identity.set_user メソッドが使用できるようになりました。これは、トレースにユーザ情報を追加するための推奨 API です。

# アクティブトレースを取得する
trace = Datadog::Tracing.active_trace

# 必須ユーザー ID タグを設定する
Datadog::Kit::Identity.set_user(trace, id: 'd131dd02c56eeec4')

# または、オプションのユーザーモニタリングタグを設定する
Datadog::Kit::Identity.set_user(
  trace,

  # 必須 ID
  id: 'd131dd02c56eeec4',

  #セマティクスが分かっているオプションタグ
  name: 'Jean Example',
  email:, 'jean.example@example.com',
  session_id:, '987654321',
  role: 'admin',
  scope: 'read:message, write:files',

  # オプションの自由形式タグ
  another_tag: 'another_value',
)

Datadog::Kit::Identity.set_user がニーズに合わない場合は、代わりに set_tag を使用することができます。

ユーザーモニタリングタグは、トレースに適用され、プレフィックス usr. の後にフィールド名が続きます。例えば、usr.name は、ユーザーの名前を追跡するユーザーモニタリングタグです。

以下の例では、アクティブトレースを取得し、関連するユーザーモニタリングタグを追加する方法を示しています。

:

  • タグの値は文字列でなければなりません。
  • usr.id タグは必須です。
# アクティブトレースを取得する
trace = Datadog::Tracing.active_trace

# 必須ユーザー ID タグを設定する
trace.set_tag('usr.id', 'd131dd02c56eeec4')

# セマティクスが分かっているユーザーモニタリングタグをオプションで設定する
trace.set_tag('usr.name', 'Jean Example')
trace.set_tag('usr.email', 'jean.example@example.com')
trace.set_tag('usr.session_id', '987654321')
trace.set_tag('usr.role', 'admin')
trace.set_tag('usr.scope', 'read:message, write:files')

# 自由形式のタグを設定する
trace.set_tag('usr.another_tag', 'another_value')

PHP トレーサーは \DDTrace\set_user() 関数を提供し、認証されたリクエストを監視したりブロックしたりすることができます。

\DDTrace\set_user() はトレースに関連するユーザータグとメタデータを追加し、ユーザーブロックを自動的に実行します。

以下の例では、ユーザー監視タグを設定し、ユーザーブロックを有効にする方法を示します。

<?php
// ブロッキングは、set_user コールにより内部で行われます。
\DDTrace\set_user(
    // ユーザーの一意な識別子が必要です。
    '123456789',

    // その他のフィールドはすべてオプションです。
    [
        'name' =>  'Jean Example',
        'email' => 'jean.example@example.com',
        'session_id' => '987654321',
        'role' => 'admin',
        'scope' => 'read:message, write:files',
    ]
);
?>

Node トレーサーパッケージは tracer.setUser(user) 関数を提供し、トレースにユーザー情報を追加することで認証されたリクエストを監視できるようにします。

以下の例では、関連するユーザー監視タグを追加し、ユーザーブロック機能を有効にする方法を示しています。

const tracer = require('dd-trace').init()

function handle () {
  tracer.setUser({
    id: '123456789', // *必須* ユーザーの一意な識別子。

    // その他のフィールドはすべてオプションです。
    email: 'jane.doe@example.com', // ユーザーのメールアドレス。
    name: 'Jane Doe', // ユーザーのユーザーフレンドリーな名前。
    session_id: '987654321', // ユーザーのセッション ID。
    role: 'admin', // ユーザーがリクエストしたロール。
    scope: 'read:message, write:files', // ユーザーが現在持っているスコープまたは付与された権限。

    // ユーザーへのカスタムデータ (RBAC、Oauth など) をアタッチするために、任意のフィールドも受け付けます
    custom_tag: 'custom data'
  })

// 現在認証されているユーザーを設定し、ブロックされているかどうかを確認します
if (tracer.appsec.isUserBlocked(user)) {  // また、現在認証されているユーザーを設定します
  return tracer.appsec.blockRequest(req, res) // ブロック応答が送信されます
  }

}

情報およびオプションについては、Node.js トレーサーのドキュメントをお読みください。

Python トレーサーパッケージが提供する set_user 関数を用いて、トレースにユーザー情報を追加することで、認証済みリクエストを監視します。

この例では、ユーザー監視タグを設定し、ユーザーブロック機能を有効にする方法を示します。

from ddtrace.contrib.trace_utils import set_user
from ddtrace import tracer
# set_user() を呼び出し、現在認証されているユーザー ID をトレースします
user_id = "some_user_id"
set_user(tracer, user_id, name="John", email="test@test.com", scope="some_scope",
         role="manager", session_id="session_id", propagate=True)

ビジネスロジック情報 (ログイン成功、ログイン失敗、任意のビジネスロジック) のトレースへの追加

dd-trace-java v1.8.0 からは、Java トレーサーの API を使用してユーザーイベントを追跡することができます。

次の例は、ログインイベントやカスタムイベント (サインアップを例とする) を追跡する方法を示しています。

import datadog.trace.api.EventTracker;
import datadog.trace.api.GlobalTracer;

public class LoginController {

    private User doLogin(String userName, String password) {
        // this is where you get User based on userName/password credentials
        User user = checkLogin(userName, password);

        Map<String, String> metadata = new HashMap<>();
        metadata.put("email", user.getEmail());

        // track user authentication success events
        GlobalTracer
            .getEventTracker()
            .trackLoginSuccessEvent(user.getId(), metadata);

    }
}
import datadog.trace.api.EventTracker;
import datadog.trace.api.GlobalTracer;

public class LoginController {

    private User doLogin(String userName, String password) {
        // this is where you get User based on userName/password credentials
        User user = checkLogin(userName, password);

        // if function returns null - user doesn't exist
        boolean userExists = (user != null);
        String userId = null;
        Map<String, String> metadata = new HashMap<>();
        if (userExists != null) {
            userId = getUserId(userName)
            metadata.put("email", user.getEmail());
        } else {
            userId = user.getEmail();
        }

        // track user authentication error events
        GlobalTracer
            .getEventTracker()
            .trackLoginFailureEvent(userId, userExists, metadata);
    }
}
import datadog.trace.api.EventTracker;
import datadog.trace.api.GlobalTracer;

public class LoginController {

    private User doSignup(String userId, String email) {
        // ここで、ユーザーアカウントを作成します
        User user = createUser(userId, email);

        Map<String, String> metadata = new HashMap<>();
        metadata.put("email", user.getEmail());
        metadata.put("id", user.getId());

        // ユーザーサインアップイベントを追跡します
        GlobalTracer
            .getEventTracker()
            .trackCustomEvent("users.signup", metadata);
    }
}

dd-trace-dotnet v2.23.0 からは、.NET トレーサーの API を使用してユーザーイベントを追跡することができます。

次の例は、ログインイベントやカスタムイベント (サインアップを例とする) を追跡する方法を示しています。

using Datadog.Trace.AppSec;

void OnLogonSuccess(string userId, ...)
{
    // metadata はオプションです
    var metadata = new Dictionary<string, string>()
    {
        { "customKey", "customValue" }
    };
    EventTrackingSdk.TrackUserLoginSuccessEvent(userId, metadata);

    // ...
}
using Datadog.Trace.AppSec;

void OnLogonFailure(string userId, bool userExists, ...)
{
    // If no userId can be provided, any unique user identifier (username, email...) may be used
    // metadata is optional
    var metadata = new Dictionary<string, string>()
    {
        { "customKey", "customValue" }
    };
    EventTrackingSdk.TrackUserLoginFailureEvent(userId, userExists, metadata);

    // ...
}
void OnUserSignupComplete(string userId, ...)
{
    // metadata パラメーターはオプションですが、"usr.id" を追加します
    var metadata = new Dictionary<string, string>()
    {
        { "usr.id", userId }
    };
    // カスタムビジネスロジックの追跡を活用し、ユーザーのサインアップを追跡します
    EventTrackingSdk.TrackCustomEvent("users.signup", metadata);

    // ...
}

dd-trace-go v1.47.0 からは、Go トレーサーの API を使用してユーザーイベントを追跡することができます。

次の例は、ログインイベントやカスタムイベント (サインアップを例とする) を追跡する方法を示しています。

import "gopkg.in/DataDog/dd-trace-go.v1/appsec"

func handler(w http.ResponseWriter, r *http.Request) {
  metadata := /* optional extra event metadata */
  userdata := /* optional extra user data */

  // Track login success, replace `my-uid` by a unique identifier of the user (such as numeric, username, and email)
  if appsec.TrackUserLoginSuccessEvent(r.Context(), "my-uid", metadata, userdata) != nil {
    // The given user id is blocked and the handler should be aborted asap.
    // The blocking response will be sent by the appsec middleware.
    return
  }
}
import "gopkg.in/DataDog/dd-trace-go.v1/appsec"

func handler(w http.ResponseWriter, r *http.Request) {
  exists := /* whether the given user id exists or not */
  metadata := /* optional extra event metadata */ 
  // Replace `my-uid` by a unique identifier of the user (numeric, username, email...)
  appsec.TrackUserLoginFailureEvent(r.Context(), "my-uid", exists, metadata)
}
import "gopkg.in/DataDog/dd-trace-go.v1/appsec"

func handler(w http.ResponseWriter, r *http.Request) {
  metadata := map[string]string{"usr.id": "my-uid"}

  // カスタムビジネスロジックの追跡を活用し、ユーザーのサインアップを追跡します
  appsec.TrackCustomEvent(r.Context(), "users.signup", metadata)
}

dd-trace-rb v1.9.0 からは、Ruby トレーサーの API を使用してユーザーイベントを追跡することができます。

次の例は、ログインイベントやカスタムイベント (サインアップを例とする) を追跡する方法を示しています。

ログインの成功/失敗イベントを含むトレースは、以下のクエリ @appsec.security_activity:business_logic.users.login.success または @appsec.security_activity:business_logic.users.login.failure を使用してクエリすることができます。

require 'datadog/kit/appsec/events'

trace = Datadog::Tracing.active_trace
# Replace `my_user_id` by a unique identifier of the user (numeric, username, email...)
Datadog::Kit::AppSec::Events.track_login_success(trace, user: { id: 'my_user_id' })
require 'datadog/kit/appsec/events'
trace = Datadog::Tracing.active_trace

# Replace `my_user_id` by a unique identifier of the user (numeric, username, email...)

# if the user exists
Datadog::Kit::AppSec::Events.track_login_failure(trace, user_id: 'my_user_id', user_exists: true)

# if the user doesn't exist
Datadog::Kit::AppSec::Events.track_login_failure(trace, user_id: 'my_user_id', user_exists: false)
require 'datadog/kit/appsec/events'
trace = Datadog::Tracing.active_trace

# カスタムビジネスロジックの追跡を活用し、ユーザーのサインアップを追跡します
Datadog::Kit::AppSec::Events.track('users.signup', trace)

dd-trace-php v0.84.0 からは、PHP トレーサーの API を使用してユーザーイベントを追跡することができます。

次の例は、ログインイベントやカスタムイベント (サインアップを例とする) を追跡する方法を示しています。

<?php
\datadog\appsec\track_user_login_success_event($id, ['email' => $email])
?>
<?php
// If no numeric userId is available, you may use any unique string as userId instead (username, email...)
// Make sure that the value is unique per user (and not per attacker/IP)
\datadog\appsec\track_user_login_failure_event($id, $exists, ['email' => $email])
?>
<?php
\datadog\appsec\track_custom_event('users.signup', ['id' => $id, 'email' => $email]);
?>

dd-trace-js v3.13.1 からは、NodeJS トレーサーの API を使用してユーザーイベントを追跡することができます。

次の例は、ログインイベントやカスタムイベント (サインアップを例とする) を追跡する方法を示しています。

const tracer = require('dd-trace')

// in a controller:
const user = {
  id: 'user-id', // id is mandatory, if no numeric ID is available, any unique identifier will do (username, email...)
  email: 'user@email.com' // other fields are optional
}
const metadata = { custom: 'value' } // optional metadata with arbitrary fields

// Log a successful user authentication event
tracer.appsec.trackUserLoginSuccessEvent(user, metadata) // metadata is optional
const tracer = require('dd-trace')

// in a controller:
const userId = 'user-id' // if no numeric ID is available, any unique identifier will do (username, email...)
const userExists = true // if the user login exists in database for example
const metadata = { custom: 'value' } // optional metadata with arbitrary fields

// metadata is optional
tracer.appsec.trackUserLoginFailureEvent(userId, userExists, metadata)
const tracer = require('dd-trace')

// コントローラーで
const eventName = 'users.signup'
const metadata = { 'usr.id': 'user-id' }

tracer.appsec.trackCustomEvent(eventName, metadata)

dd-trace-py v1.9.0 からは、Python トレーサーの API を使用してユーザーイベントを追跡することができます。

次の例は、ログインイベントやカスタムイベント (サインアップを例とする) を追跡する方法を示しています。

from ddtrace.appsec.trace_utils import track_user_login_success_event
from ddtrace import tracer
metadata = {"custom": "customvalue"}
# name、email、scope、role、session_id、propagate はオプションの引数で、
# デフォルトは None ですが propagate はデフォルトが True になります。
# これらは set_user() 関数に渡されます
track_user_login_success_event(tracer, "userid", metadata)
from ddtrace.appsec.trace_utils import track_user_login_failure_event
from ddtrace import tracer
metadata = {"custom": "customvalue"}
# exists indicates if the failed login user exists in the system
exists = False
# if no numeric userId is available, any unique identifier will do (username, email...)
track_user_login_failure_event(tracer, "userid", exists, metadata)
from ddtrace.appsec.trace_utils import track_custom_event
from ddtrace import tracer
metadata = {"usr.id": "userid"}
event_name = "users.signup"
track_custom_event(tracer, event_name, metadata)

コードを変更せずにビジネスロジック情報を追跡する

サービスで ASM が有効になっており、リモート構成が有効になっている場合、カスタムのビジネスロジックタグと一致するリクエストにフラグを立てるカスタム WAF ルールを作成することができます。この場合、アプリケーションを変更する必要はなく、すべて Datadog から行うことができます。

まず、Custom WAF Rule ページに移動し、“Create New Rule” をクリックします。

ASM ホームページから Protection、In-App WAF、Custom Rules の順にクリックして、Custom WAF Rule メニューにアクセス

カスタム WAF ルールを定義するためのメニューが開きます。“Business Logic” カテゴリーを選択すると、イベントタイプ (例: users.password_reset) を構成できるようになります。次に、追跡したいサービスと特定のエンドポイントを選択します。また、ルール条件を使用して特定のパラメーターをターゲットにし、_インスツルメント_したいコードフローを特定することもできます。条件が一致すると、ライブラリがトレースにタグを付け、それを ASM に転送するフラグを立てます。条件が不要な場合は、すべてに一致する大まかな条件を設定することもできます。

Create New Rule ボタンをクリックした際に表示されるフォームのスクリーンショット

ルールが保存されると、リモート構成が有効になっているサービスのインスタンスにデプロイされます。

ユーザーアクティビティイベントの自動追跡

When ASM is enabled, Datadog Tracing Libraries attempt to detect user activity events automatically.

自動検出できるイベントは以下の通りです。

  • users.login.success
  • users.login.failure
  • users.signup

Automatic user activity event tracking modes

Automatic user activity tracking offers the following modes:

  • identification mode (short name: ident):
    • This mode is the default and always collects the user ID or best effort.
    • The user ID is collected on login success and login failure. With failure, the user ID is collected regardless of whether the user exists or not.
    • When the instrumented framework doesn’t clearly provide a user ID, but rather a structured user object, the user ID is determined on a best effort basis based on the object field names. This list of field names are considered, ordered by priority:
      • id
      • email
      • username
      • login
      • user
    • If no user ID is available or found, the user event is not emitted.
  • anonymization mode (short name: anon):
    • This mode is the same as identification, but anonymizes the user ID.
  • disabled mode:
    • ASM libraries do not collect any user ID from their automated instrumentations.
    • User login events are not emitted.
All modes only affect automated instrumentation. The modes don't apply to manual collection. Manual collection is configured using an SDK, and those settings are not overridden by automated instrumentation.

Datadog libraries allow you to configure auto-instrumentation by using the DD_APPSEC_AUTO_USER_INSTRUMENTATION_MODE environment variable with the short name for the mode: ident|anon|disabled.

The default mode is identification mode (short name: ident).

For example, DD_APPSEC_AUTO_USER_INSTRUMENTATION_MODE=anon.

Deprecated modes

Previous modes are deprecated, but compatibility will be maintained until the next major release.

The following modes are deprecated:

  • safe mode: The trace library does not include any PII information on the events metadata. The tracer library tries to collect the user ID, and only if the user ID is a valid GUID
  • extended mode: The trace library tries to collect the user ID, and the user email. In this mode, Datadog does not check the type for the user ID to be a GUID. The trace library reports whatever value can be extracted from the event.

Note: There could be cases in which the trace library won’t be able to extract any information from the user event. The event would be reported with empty metadata. In those cases, use the SDK to manually instrument the user events.

ユーザーアクティビティイベントの自動追跡を無効にする

If you wish to disable the detection of these events, you should set the environment variable DD_APPSEC_AUTOMATED_USER_EVENTS_TRACKING_ENABLED to false. This should be set on the application hosting the Datadog Tracing Library, and not on the Datadog Agent.

The previous environment variable was named DD_APPSEC_AUTOMATED_USER_EVENTS_TRACKING.

その他の参考資料