# 安全な署名

[トランザクション](/ja/docs/concepts/transactions)をXRP Ledgerに送信するには、[秘密鍵](/ja/docs/concepts/accounts/cryptographic-keys)のセキュリティを損なわない方法でトランザクションにデジタル署名する必要があります。（他の人があなたの秘密鍵にアクセスできる場合、その人はあなたと同じようにあなたのアカウントを操作できるため、すべての資金が盗まれたり消却されたりする可能性があります。）このページでは、トランザクションに安全に署名できる環境の設定方法について説明します。

ネットワークにトランザクションを送信していない場合は、Rippleが運用しているサーバなど、信頼できる公開サーバを安全に使用して、着信トランザクションの監視やその他のネットワークアクティビティの読み取りを行うことができます。XRP Ledgerのすべてのトランザクション、残高、データは公開されています。

セキュリティのレベルが異なるさまざまな構成があるため、状況に応じて適したものは異なります。次の中からニーズに最適なものを選択してください。

- [`rippled`をローカルで実行](#%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%AB%E3%81%A7rippled%E3%82%92%E5%AE%9F%E8%A1%8C%E3%81%99%E3%82%8B)または[同じLAN内で実行](#%E5%90%8C%E3%81%98lan%E5%86%85%E3%81%A7rippled%E3%82%92%E5%AE%9F%E8%A1%8C%E3%81%99%E3%82%8B)
- ローカル署名を行える[クライアントライブラリを使用](#%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%AB%E7%BD%B2%E5%90%8D%E6%A9%9F%E8%83%BD%E3%81%AE%E3%81%82%E3%82%8B%E3%82%AF%E3%83%A9%E3%82%A4%E3%82%A2%E3%83%B3%E3%83%88%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B)
- XRP Ledgerの署名に対応した[専用の署名デバイスを使用](#%E5%B0%82%E7%94%A8%E3%81%AE%E7%BD%B2%E5%90%8D%E3%83%87%E3%83%90%E3%82%A4%E3%82%B9%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B)
- 信頼できる[リモート`rippled`マシンに接続するために安全なVPNを使用](#%E3%83%AA%E3%83%A2%E3%83%BC%E3%83%88rippled%E3%82%B5%E3%83%BC%E3%83%90%E3%81%AB%E5%AF%BE%E3%81%97%E3%81%A6%E5%AE%89%E5%85%A8%E3%81%AAvpn%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B)


## 安全でない構成

[](/assets/insecure-signing-options.2dc3d634de9f562fb69f0720e17cf9a2a33c41347e3ef667c71234fda24a467c.ac57e6ef.svg)

外部のソースからあなたの秘密鍵にアクセスできる構成は危険で、不正使用者によってあなたのすべてのXRP（およびあなたのXRP Ledgerのアドレスにあるすべてのもの）が盗まれる可能性があります。そのような構成の例としては、インターネット経由で他の人の`rippled`サーバの[signメソッド](/ja/docs/references/http-websocket-apis/admin-api-methods/signing-methods/sign)を使用する構成や、秘密鍵をインターネットを経由してプレーンテキストで自己所有サーバに送信する構成などがあります。

秘密鍵の秘匿性は常に保持する必要があります。自分にメールで送信したり、人の目に触れるところで入力したりしてはいけません。秘密鍵を使用しないときは、決してプレーンテキストではなく、暗号化された形式で保存する必要があります。セキュリティと利便性のバランスは、アドレスの保有額によっても変わります。さまざまな目的に合わせてさまざまなセキュリティ構成の複数のアドレスを使用することをお勧めします。

## ローカルでrippledを実行する

[](/assets/secure-signing-local-rippled.eee564828470d65e6066ccc3012f7db431c84d8cf59b041b1cc4a7aa83759a36.ac57e6ef.svg)

この構成では、トランザクションを生成するマシンで`rippled`を実行します。  秘密鍵はマシンから出ていかないため、マシンへのアクセス権がない人は秘密鍵にアクセスできません。もちろん、マシンのセキュリティ保護に関する業界標準のプラクティスに従ってください。この構成を使用するには、次の手順を実行します。

1. [`rippled`をインストール](/ja/docs/infrastructure/installation)します。
ローカルマシンが[`rippled`の最小システム要件](/ja/docs/infrastructure/installation/system-requirements)を満たしていることを確認します。
2. トランザクションに署名する必要がある場合は、`localhost`または`127.0.0.1`のサーバに接続します。シングル署名の場合は[signメソッド](/ja/docs/references/http-websocket-apis/admin-api-methods/signing-methods/sign)、マルチシグの場合は[sign_forメソッド](/ja/docs/references/http-websocket-apis/admin-api-methods/signing-methods/sign_for)を使用します。
[構成ファイルの例](https://github.com/XRPLF/rippled/blob/8429dd67e60ba360da591bfa905b58a35638fda1/cfg/rippled-example.cfg#L1050-L1073)では、ローカルループバックネットワーク上（127.0.0.1）のポート5005でJSON-RPC（HTTP）、ポート6006でWebSocket（WS）の接続をリッスンし、接続されるすべてのクライアントを管理者として扱っています。
署名に[コマンドラインAPI](/ja/docs/references/http-websocket-apis/api-conventions/request-formatting#%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%83%A9%E3%82%A4%E3%83%B3%E5%BD%A2%E5%BC%8F)を使用する場合は、コマンドラインでないクライアントで[Websocket APIやJSON-RPC APIを使用](/docs/tutorials/get-started/get-started-http-websocket-apis)する場合よりもセキュリティが弱くなります。コマンドライン構文を使用すると、秘密鍵がシステムのプロセスリストで他のユーザに見える可能性があり、シェル履歴にプレーンテキスト形式でキーが保存される可能性があります。
3. サーバの使用中は、稼働状態と最新状態を維持して、ネットワークと同期されるようにしておく必要があります。
トランザクションを送信していないときは`rippled`サーバをオフにすることが *可能* ですが、再び起動したときにネットワークとの同期に最大15分かかります。


## 同じLAN内でrippledを実行する

[](/assets/secure-signing-lan-rippled.4338d1073b8667f29a581401f887c60ad6bbb4b8f3861e09eaaf649797126cab.ac57e6ef.svg)

この構成では、署名するトランザクションを生成するマシンと同じプライベートローカルエリアネットワーク（LAN）内の専用マシンで`rippled`サーバを実行します。この構成では、`rippled`を実行する専用の1台のマシンを使用しながら、中程度のシステムスペックの1台以上のマシンでトランザクションの指示を組み立てることができます。自己所有のデータセンターやサーバルームがある場合に魅力的な選択肢です。

この構成を使用するには、`rippled`サーバをLAN内の`wss`および`https`接続を受け入れるように設定します。[証明書ピンニング](https://en.wikipedia.org/wiki/Transport_Layer_Security#Certificate_pinning)を使用する場合は自己署名証明書を使用できます。あるいは、社内や既知の認証局が署名した証明書を使用できます。[Let's Encrypt](https://letsencrypt.org/)などの一部の認証局は無料で証明書を自動発行しています。

必ず、マシンのセキュリティ保護に関する業界標準のプラクティスに従ってください。例えば、ファイアウォール、ウイルス対策、適切なユーザ権限を使用するなどです。

## ローカル署名機能のあるクライアントライブラリを使用する

[](/assets/secure-signing-client-library.b3cd25c60278c248c367b79c8eccbf42a147dc92beba0da7c4713fdda4782e8c.ac57e6ef.svg)

この構成では、使用するプログラミング言語で、署名を組み込んだクライアントライブラリを使用します。ローカル署名を実行できるライブラリの一覧は、[クライアントライブラリ](/ja/docs/references/client-libraries)をご覧ください。

### 署名ライブラリのセキュリティベストプラクティス

署名ライブラリのセキュリティを最適化するために、次のベストプラクティスを使用してください。

* 使用する署名ライブラリが、署名アルゴリズムを適切かつ安全に実装 していることを確認してください。例えば、ライブラリがデフォルトのECDSAアルゴリズムを使用する場合、[RFC-6979](https://tools.ietf.org/html/rfc6979)に記述されているように、決定論的なnoncesも使用すべきです。
上記のすべての公開ライブラリは、業界のベストプラクティスに従っています。
* クライアントライブラリを最新の安定版に更新してください。
* セキュリティ強化のため、[Vault](https://www.vaultproject.io/)などの管理ツールから秘密鍵を読み込みます。


### ローカル署名の例

以下は、以下の言語とライブラリを使用して、ローカルでトランザクションに署名する方法の例です。

* **JavaScript** / **TypeScript** - [`xrpl.js`](https://github.com/XRPLF/xrpl.js)
* **Python** - [`xrpl-py`](https://github.com/XRPLF/xrpl-py)
* **Java** - [`xrpl4j`](https://github.com/XRPLF/xrpl4j)


JavaScript

```js
// Sample code demonstrating secure offline signing using xrpl.js library.
const xrpl = require('xrpl')

// Load seed value from an environment variable:
const my_wallet = xrpl.Wallet.fromSeed(process.env['MY_SEED'])

// For offline signing, you need to know your address's next Sequence number.
// Alternatively, you could use a Ticket in place of the Sequence number.
// This is useful when you need multiple signatures and may want to process transactions out-of-order.
// For details, see: https://xrpl.org/tickets.html
let my_seq = 21404872

// Provide *all* required fields before signing a transaction
const txJSON = {
  "Account": my_wallet.address,
  "TransactionType":"Payment",
  "Destination":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
  "DeliverMax":"13000000",
  "Flags":2147483648,
  "LastLedgerSequence":7835923, // Optional, but recommended.
  "Fee":"13",
  "Sequence": my_seq
}

const signed = my_wallet.sign(txJSON)

console.log("tx_blob is:", signed.tx_blob)
console.log("tx hash is:", signed.tx_json.hash)
```

Python

```py
# Define signer address
import os  
my_secret = os.getenv("MYSECRET")
from xrpl.wallet import Wallet
wallet = Wallet.from_seed(seed=my_secret)
print(wallet.address)  # "raaFKKmgf6CRZttTVABeTcsqzRQ51bNR6Q"

# For offline signing, you need to know your address's next Sequence number.
# Alternatively, you could use a Ticket in place of the Sequence number.
# This is useful when you need multiple signatures and may want to process transactions out-of-order.
# For details, see: https://xrpl.org/tickets.html
sequence = 0

from xrpl.models.transactions import Payment
from xrpl.utils import xrp_to_drops
my_payment = Payment(
    account=wallet.address,
    amount=xrp_to_drops(22),
    fee="10",
    destination="rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe",
    sequence=sequence,
)
print("Payment object:", my_payment)

# Sign transaction -------------------------------------------------------------
import xrpl.transaction 
signed = xrpl.transaction.sign(my_payment, wallet)
print("Signed transaction blob:", signed)
```

Java

```java
////////////////////////////////////////////////////////////////////////////
// Sign using a SingleKeySignatureService:
// This implementation of SignatureService signs Transactions using a
// supplied PrivateKey. This may be suitable for some applications, but is
// likely not secure enough for server side applications, as keys should not
// be stored in memory whenever possible.
////////////////////////////////////////////////////////////////////////////

// Create a random wallet
KeyPair randomKeyPair = Seed.ed25519Seed().deriveKeyPair();
PublicKey publicKey = randomKeyPair.publicKey();
PrivateKey privateKey = randomKeyPair.privateKey()

// Construct a SignatureService
SignatureService<PrivateKey> signatureService = new BcSignatureService();

// Construct and sign the Payment
Payment payment = Payment.builder()
  .account(publicKey.deriveAddress())
  .destination(Address.of("rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe"))
  .amount(XrpCurrencyAmount.ofDrops(1000))
  .fee(XrpCurrencyAmount.ofDrops(10))
  .sequence(UnsignedInteger.valueOf(16126889))
  .signingPublicKey(publicKey)
  .build();
SingleSignedTransaction<Payment> signedPayment = signatureService.sign(privateKey, payment);
System.out.println("Signed Payment: " + signedPayment.signedTransaction());


////////////////////////////////////////////////////////////////////////////
// Sign using a DerivedKeysSignatureService:
// This implementation of SignatureService deterministically derives
// Private Keys from a secret value (likely a server secret) and a wallet
// identifier. That PrivateKey can then be used to sign transactions.
// The wallet identifier can be anything, but would likely be an existing ID
// tracked by a server side system.
//
// Though this implementation is more secure than SingleKeySignatureService
// and better suited for server-side applications, keys are still held
// in memory. For the best security, we suggest using a HSM-based
// implementation.
////////////////////////////////////////////////////////////////////////////

// Construct a DerivedKeysSignatureService with a server secret (in this case "shh")
SignatureService<PrivateKeyReference> derivedKeySignatureService = new BcDerivedKeySignatureService(
  () -> ServerSecret.of("shh".getBytes())
);

PrivateKeyReference privateKeyReference = new PrivateKeyReference() {
  @Override
  public KeyType keyType() {
    return KeyType.ED25519;
  }

  @Override
  public String keyIdentifier() {
    return "sample-keypair";
  }
};

// Get the public key and classic address for the given walletId
PublicKey publicKey = derivedKeySignatureService.derivePublicKey(privateKeyReference);
Address classicAddress = publicKey.deriveAddress();

// Construct and sign the Payment
Payment payment = Payment.builder()
  .account(classicAddress)
  .destination(Address.of("rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe"))
  .amount(XrpCurrencyAmount.ofDrops(1000))
  .fee(XrpCurrencyAmount.ofDrops(10))
  .sequence(UnsignedInteger.valueOf(16126889))
  .signingPublicKey(publicKey)
  .build();

SingleSignedTransaction<Payment> signedPayment = derivedKeySignatureService.sign(privateKeyReference, payment);
System.out.println("Signed Payment: " + signedPayment.signedTransaction());
```

## 専用の署名デバイスを使用する

[](/assets/secure-signing-dedicated-hardware.f350eea2904a27931ec5e72faef200b4c88c7f0305d13e1da49d93cbded62a52.ac57e6ef.svg)

専用の署名デバイスが各社から販売されており、例えば[Ledger Nano S](https://www.ledger.com/products/ledger-nano-s)は、秘密鍵をデバイスから出さずに使ってXRP Ledgerトランザクションに署名できます。すべてのタイプのトランザクションに対応していないデバイスもあります。

この構成の設定は、特定のデバイスによって異なります。場合によっては、署名デバイスと通信するためにマシンで「マネージャー」アプリケーションを実行する必要があります。そのようなデバイスの設定と使用方法については、メーカーの手順をご覧ください。

## リモートrippledサーバに対して安全なVPNを使用する

[](/assets/secure-signing-over-vpn.2d5c76c17db52931449a9b0d1fdb849b180dc065b9463756529e5e0c69ef0f05.ac57e6ef.svg)

この構成では、コロケーション施設や遠隔地のデータセンターなどにあるリモートでホストされている`rippled`サーバを使用し、暗号化されたVPNを使用してそのサーバに接続します。

この構成を使用するには、[プライベートLANで`rippled`を実行](#%E5%90%8C%E3%81%98lan%E5%86%85%E3%81%A7rippled%E3%82%92%E5%AE%9F%E8%A1%8C%E3%81%99%E3%82%8B)するための手順に従いますが、VPNを使用してリモート`rippled`サーバのLANに接続します。VPNの設定手順は環境によって異なり、このガイドでは説明しません。

## 関連項目

- **コンセプト:**
  - [暗号鍵](/ja/docs/concepts/accounts/cryptographic-keys)
  - [マルチシグ](/ja/docs/concepts/accounts/multi-signing)
- **チュートリアル:**
  - [rippledのインストール](/ja/docs/infrastructure/installation)
  - [レギュラーキーペアの割り当て](/ja/docs/tutorials/best-practices/key-management/assign-a-regular-key-pair)
  - [信頼できるトランザクションの送信](/ja/docs/concepts/transactions/reliable-transaction-submission)
  - [パブリック署名の有効化](/ja/docs/infrastructure/configuration/enable-public-signing)
- **リファレンス:**
  - [signメソッド](/ja/docs/references/http-websocket-apis/admin-api-methods/signing-methods/sign)
  - [submitメソッド](/ja/docs/references/http-websocket-apis/public-api-methods/transaction-methods/submit)
  - [xrpl.jsリファレンス](https://js.xrpl.org/)
  - [`xrpl-py`リファレンス](https://xrpl-py.readthedocs.io/)
  - [`xrpl4j` Reference](https://javadoc.io/doc/org.xrpl/)