Merge branch '592-scrub-addresses-before-logging-them' into 'master'

Scrub addresses before logging them

MAC, IP and onion addresses are now scrubbed before logging to ensure we don't leave any sensitive information in plaintext on the device or send it in crash reports or feedback.

* Bluetooth MAC addresses keep the first and last octets
* IPv4 addresses keep the first and last octets
* IPv6 addresses should be scrubbed completely (couldn't test)
* Onion addresses keep the first three characters

If an address is invalid it will not be scrubbed to enable debugging, because it is most likely not sensitive.

Closes #592

See merge request !290
This commit is contained in:
akwizgran
2016-08-24 17:18:48 +00:00
6 changed files with 119 additions and 33 deletions

View File

@@ -57,6 +57,7 @@ import static android.bluetooth.BluetoothDevice.EXTRA_DEVICE;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static org.briarproject.util.PrivacyUtils.scrubMacAddress;
class DroidtoothPlugin implements DuplexPlugin {
@@ -172,7 +173,7 @@ class DroidtoothPlugin implements DuplexPlugin {
String address = AndroidUtils.getBluetoothAddress(appContext,
adapter);
if (LOG.isLoggable(INFO))
LOG.info("Local address " + address);
LOG.info("Local address " + scrubMacAddress(address));
if (!StringUtils.isNullOrEmpty(address)) {
// Advertise the Bluetooth address to contacts
TransportProperties p = new TransportProperties();
@@ -237,7 +238,7 @@ class DroidtoothPlugin implements DuplexPlugin {
}
if (LOG.isLoggable(INFO)) {
String address = s.getRemoteDevice().getAddress();
LOG.info("Connection from " + address);
LOG.info("Connection from " + scrubMacAddress(address));
}
backoff.reset();
callback.incomingConnectionCreated(wrapSocket(s));
@@ -307,6 +308,7 @@ class DroidtoothPlugin implements DuplexPlugin {
// Validate the address
if (!BluetoothAdapter.checkBluetoothAddress(address)) {
if (LOG.isLoggable(WARNING))
// not scrubbing here to be able to figure out the problem
LOG.warning("Invalid address " + address);
return null;
}
@@ -323,13 +325,15 @@ class DroidtoothPlugin implements DuplexPlugin {
BluetoothSocket s = null;
try {
s = d.createInsecureRfcommSocketToServiceRecord(u);
if (LOG.isLoggable(INFO)) LOG.info("Connecting to " + address);
if (LOG.isLoggable(INFO))
LOG.info("Connecting to " + scrubMacAddress(address));
s.connect();
if (LOG.isLoggable(INFO)) LOG.info("Connected to " + address);
if (LOG.isLoggable(INFO))
LOG.info("Connected to " + scrubMacAddress(address));
return s;
} catch (IOException e) {
if (LOG.isLoggable(INFO))
LOG.info("Failed to connect to " + address);
LOG.info("Failed to connect to " + scrubMacAddress(address));
tryToClose(s);
return null;
}
@@ -567,7 +571,8 @@ class DroidtoothPlugin implements DuplexPlugin {
} else if (action.equals(FOUND)) {
BluetoothDevice d = intent.getParcelableExtra(EXTRA_DEVICE);
if (LOG.isLoggable(INFO))
LOG.info("Discovered device: " + d.getAddress());
LOG.info("Discovered device: " +
scrubMacAddress(d.getAddress()));
addresses.add(d.getAddress());
}
}

View File

@@ -72,6 +72,7 @@ import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static net.freehaven.tor.control.TorControlCommands.HS_ADDRESS;
import static net.freehaven.tor.control.TorControlCommands.HS_PRIVKEY;
import static org.briarproject.util.PrivacyUtils.scrubOnion;
class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
@@ -405,7 +406,8 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
}
// Publish the hidden service's onion hostname in transport properties
String hostname = response.get(HS_ADDRESS);
if (LOG.isLoggable(INFO)) LOG.info("Hidden service " + hostname);
if (LOG.isLoggable(INFO))
LOG.info("Hidden service " + scrubOnion(hostname));
TransportProperties p = new TransportProperties();
p.put(PROP_ONION, hostname);
callback.mergeLocalProperties(p);
@@ -510,21 +512,25 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
String onion = p.get(PROP_ONION);
if (StringUtils.isNullOrEmpty(onion)) return null;
if (!ONION.matcher(onion).matches()) {
// not scrubbing this address, so we are able to find the problem
if (LOG.isLoggable(INFO)) LOG.info("Invalid hostname: " + onion);
return null;
}
try {
if (LOG.isLoggable(INFO)) LOG.info("Connecting to " + onion);
if (LOG.isLoggable(INFO))
LOG.info("Connecting to " + scrubOnion(onion));
controlConnection.forgetHiddenService(onion);
Socks5Proxy proxy = new Socks5Proxy("127.0.0.1", SOCKS_PORT);
proxy.resolveAddrLocally(false);
Socket s = new SocksSocket(proxy, onion + ".onion", 80);
s.setSoTimeout(socketTimeout);
if (LOG.isLoggable(INFO)) LOG.info("Connected to " + onion);
if (LOG.isLoggable(INFO))
LOG.info("Connected to " + scrubOnion(onion));
return new TorTransportConnection(this, s);
} catch (IOException e) {
if (LOG.isLoggable(INFO))
LOG.info("Could not connect to " + onion + ": " + e.toString());
LOG.info("Could not connect to " + scrubOnion(onion) + ": " +
e.toString());
return null;
}
}

View File

@@ -29,6 +29,7 @@ import java.util.logging.Logger;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static org.briarproject.util.PrivacyUtils.scrubSocketAddress;
class LanTcpPlugin extends TcpPlugin {
@@ -177,7 +178,7 @@ class LanTcpPlugin extends TcpPlugin {
break;
} catch (IOException e) {
if (LOG.isLoggable(INFO))
LOG.info("Failed to bind " + addr);
LOG.info("Failed to bind " + scrubSocketAddress(addr));
tryToClose(ss);
}
}
@@ -205,20 +206,24 @@ class LanTcpPlugin extends TcpPlugin {
if (!isConnectable(remote)) {
if (LOG.isLoggable(INFO)) {
SocketAddress local = socket.getLocalSocketAddress();
LOG.info(remote + " is not connectable from " + local);
LOG.info(scrubSocketAddress(remote) +
" is not connectable from " +
scrubSocketAddress(local));
}
return null;
}
Socket s = new Socket();
try {
if (LOG.isLoggable(INFO)) LOG.info("Connecting to " + remote);
if (LOG.isLoggable(INFO))
LOG.info("Connecting to " + scrubSocketAddress(remote));
s.connect(remote);
s.setSoTimeout(socketTimeout);
if (LOG.isLoggable(INFO)) LOG.info("Connected to " + remote);
if (LOG.isLoggable(INFO))
LOG.info("Connected to " + scrubSocketAddress(remote));
return new TcpTransportConnection(this, s);
} catch (IOException e) {
if (LOG.isLoggable(INFO))
LOG.info("Could not connect to " + remote);
LOG.info("Could not connect to " + scrubSocketAddress(remote));
return null;
}
}

View File

@@ -1,7 +1,9 @@
package org.briarproject.plugins.tcp;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import org.bitlet.weupnp.GatewayDevice;
import org.bitlet.weupnp.GatewayDiscover;
import org.briarproject.api.lifecycle.ShutdownManager;
import org.xml.sax.SAXException;
import java.io.IOException;
import java.net.InetAddress;
@@ -10,10 +12,9 @@ import java.util.logging.Logger;
import javax.xml.parsers.ParserConfigurationException;
import org.bitlet.weupnp.GatewayDevice;
import org.bitlet.weupnp.GatewayDiscover;
import org.briarproject.api.lifecycle.ShutdownManager;
import org.xml.sax.SAXException;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static org.briarproject.util.PrivacyUtils.scrubInetAddress;
class PortMapperImpl implements PortMapper {
@@ -35,7 +36,7 @@ class PortMapperImpl implements PortMapper {
InetAddress internal = gateway.getLocalAddress();
if (internal == null) return null;
if (LOG.isLoggable(INFO))
LOG.info("Internal address " + getHostAddress(internal));
LOG.info("Internal address " + scrubInetAddress(internal));
boolean succeeded = false;
InetAddress external = null;
try {
@@ -50,7 +51,8 @@ class PortMapperImpl implements PortMapper {
}
String externalString = gateway.getExternalIPAddress();
if (LOG.isLoggable(INFO))
LOG.info("External address " + externalString);
LOG.info(
"External address " + scrubInetAddress(externalString));
if (externalString != null)
external = InetAddress.getByName(externalString);
} catch (IOException e) {

View File

@@ -30,6 +30,7 @@ import java.util.regex.Pattern;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static org.briarproject.util.PrivacyUtils.scrubSocketAddress;
abstract class TcpPlugin implements DuplexPlugin {
@@ -107,14 +108,15 @@ abstract class TcpPlugin implements DuplexPlugin {
public void run() {
if (!running) return;
ServerSocket ss = null;
for (SocketAddress addr : getLocalSocketAddresses()) {
for (InetSocketAddress addr : getLocalSocketAddresses()) {
try {
ss = new ServerSocket();
ss.bind(addr);
break;
} catch (IOException e) {
if (LOG.isLoggable(INFO))
LOG.info("Failed to bind " + addr);
LOG.info("Failed to bind " +
scrubSocketAddress(addr));
tryToClose(ss);
}
}
@@ -128,9 +130,11 @@ abstract class TcpPlugin implements DuplexPlugin {
}
socket = ss;
backoff.reset();
SocketAddress local = ss.getLocalSocketAddress();
setLocalSocketAddress((InetSocketAddress) local);
if (LOG.isLoggable(INFO)) LOG.info("Listening on " + local);
InetSocketAddress local =
(InetSocketAddress) ss.getLocalSocketAddress();
setLocalSocketAddress(local);
if (LOG.isLoggable(INFO))
LOG.info("Listening on " + scrubSocketAddress(local));
callback.transportEnabled();
acceptContactConnections();
}
@@ -166,7 +170,8 @@ abstract class TcpPlugin implements DuplexPlugin {
return;
}
if (LOG.isLoggable(INFO))
LOG.info("Connection from " + s.getRemoteSocketAddress());
LOG.info("Connection from " +
scrubSocketAddress(s.getRemoteSocketAddress()));
backoff.reset();
TcpTransportConnection conn = new TcpTransportConnection(this, s);
callback.incomingConnectionCreated(conn);
@@ -223,20 +228,25 @@ abstract class TcpPlugin implements DuplexPlugin {
if (!isConnectable(remote)) {
if (LOG.isLoggable(INFO)) {
SocketAddress local = socket.getLocalSocketAddress();
LOG.info(remote + " is not connectable from " + local);
LOG.info(scrubSocketAddress(remote) +
" is not connectable from " +
scrubSocketAddress(local));
}
continue;
}
Socket s = new Socket();
try {
if (LOG.isLoggable(INFO)) LOG.info("Connecting to " + remote);
if (LOG.isLoggable(INFO))
LOG.info("Connecting to " + scrubSocketAddress(remote));
s.connect(remote);
s.setSoTimeout(socketTimeout);
if (LOG.isLoggable(INFO)) LOG.info("Connected to " + remote);
if (LOG.isLoggable(INFO))
LOG.info("Connected to " + scrubSocketAddress(remote));
return new TcpTransportConnection(this, s);
} catch (IOException e) {
if (LOG.isLoggable(INFO))
LOG.info("Could not connect to " + remote);
LOG.info("Could not connect to " +
scrubSocketAddress(remote));
}
}
return null;
@@ -255,6 +265,7 @@ abstract class TcpPlugin implements DuplexPlugin {
return new InetSocketAddress(a, p);
} catch (UnknownHostException e) {
if (LOG.isLoggable(WARNING))
// not scrubbing to enable us to find the problem
LOG.warning("Invalid address: " + addr);
return null;
} catch (NumberFormatException e) {

View File

@@ -0,0 +1,57 @@
package org.briarproject.util;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
public class PrivacyUtils {
public static String scrubOnion(String onion) {
// keep first three characters of onion address
return onion.substring(0, 3) + "[_scrubbed_]";
}
public static String scrubMacAddress(String address) {
if (address == null) return null;
// this is a fake address we need to know about
if (address.equals("02:00:00:00:00:00")) return address;
// keep first and last octet of MAC address
return address.substring(0, 3) +
"[scrubbed]" +
address.substring(14, 17);
}
public static String scrubInetAddress(InetAddress address) {
// don't scrub link and site local addresses
if (address.isLinkLocalAddress() || address.isSiteLocalAddress())
return address.toString();
// completely scrub IPv6 addresses
if (address instanceof Inet6Address) return "[scrubbed]";
// keep first and last octet of IPv4 addresses
return scrubInetAddress(address.toString());
}
public static String scrubInetAddress(String address) {
if (address == null) return null;
int firstDot = address.indexOf(".");
if (firstDot == -1) return "[scrubbed]";
String prefix = address.substring(0, firstDot + 1);
int lastDot = address.lastIndexOf(".");
String suffix = address.substring(lastDot, address.length());
return prefix + "[scrubbed]" + suffix;
}
public static String scrubSocketAddress(InetSocketAddress address) {
InetAddress inetAddress = address.getAddress();
return scrubInetAddress(inetAddress);
}
public static String scrubSocketAddress(SocketAddress address) {
if (address instanceof InetSocketAddress)
return scrubSocketAddress((InetSocketAddress) address);
return scrubInetAddress(address.toString());
}
}