Skip to content

Payjoin: randomize OHTTP relay selection to prevent network-layer fingerprinting #1906

@bc1cindy

Description

@bc1cindy

Hi there!

this issue was identified during a privacy analysis discussed in payjoin/rust-payjoin#1328, endorsed by @DanGould

BBMobile always iterates ohttpRelayUrls in fixed order in every payjoin communication. achow101 is always contacted first, revealing behavioral metadata at the network layer, even though the IP is protected by OHTTP.

 // constants.dart:50
static const List<String> ohttpRelayUrls = [
  'https://ohttp.achow101.com', // always first
  'https://pj.bobspacebkk.com',
  'https://ohttp.cakewallet.com',
];
bullbitcoin-mobile % rg ohttpRelayUrls
lib/core/utils/constants.dart
50:  static const List<String> ohttpRelayUrls = [

lib/core/payjoin/data/datasources/pdk_payjoin_datasource.dart
58:    for (final ohttpRelayUrl in PayjoinConstants.ohttpRelayUrls) {
562:      for (final ohttpRelay in PayjoinConstants.ohttpRelayUrls) {
616:    for (final ohttpRelayUrl in PayjoinConstants.ohttpRelayUrls) {
650:    for (final ohttpProxyUrl in PayjoinConstants.ohttpRelayUrls) {
703:      for (final ohttpRelay in PayjoinConstants.ohttpRelayUrls) {

Solution:
Change ohttpRelayUrls from a const to a getter that shuffles on each call:

static List<String> get ohttpRelayUrls {
  final list = [
    'https://ohttp.achow101.com',
    'https://pj.bobspacebkk.com',
    'https://ohttp.cakewallet.com',
  ];
  list.shuffle(Random.secure());
  return list;
}

since ohttpRelayUrls is only used in the 5 loops in pdk_payjoin_datasource.dart, this change requires no other modifications

I'm happy to open a PR for this

Reference:
payjoin/rust-payjoin#1328

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    Status

    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions