提交 20eeda89 authored 作者: Thomas Mueller's avatar Thomas Mueller

Use HMAC for authenticating remote LOB id's, removing the need for maintaining a…

Use HMAC for authenticating remote LOB id's, removing the need for maintaining a cache, and removing the limit on the number of LOBs per result set.
上级 57acb158
......@@ -698,7 +698,9 @@ public class SessionRemote extends SessionWithState implements DataHandler {
traceOperation("LOB_READ", (int) lobId);
transfer.writeInt(SessionRemote.LOB_READ);
transfer.writeLong(lobId);
if (clientVersion >= Constants.TCP_PROTOCOL_VERSION_12) {
transfer.writeBytes(hmac);
}
transfer.writeLong(offset);
transfer.writeInt(length);
done(transfer);
......
......@@ -37,6 +37,7 @@ import org.h2.util.SmallMap;
import org.h2.util.StringUtils;
import org.h2.value.Transfer;
import org.h2.value.Value;
import org.h2.value.ValueLobDb;
/**
* One server thread is opened per client connection.
......@@ -50,7 +51,10 @@ public class TcpServerThread implements Runnable {
private Thread thread;
private Command commit;
private SmallMap cache = new SmallMap(SysProperties.SERVER_CACHED_OBJECTS);
private SmallLRUCache<Long, CachedInputStream> lobs = SmallLRUCache.newInstance(SysProperties.SERVER_CACHED_OBJECTS);
private SmallLRUCache<Long, CachedInputStream> lobs =
SmallLRUCache.newInstance(Math.max(
SysProperties.SERVER_CACHED_OBJECTS,
SysProperties.SERVER_RESULT_SET_FETCH_SIZE * 5));
private int threadId;
private int clientVersion;
private String sessionId;
......@@ -392,14 +396,28 @@ public class TcpServerThread implements Runnable {
break;
}
case SessionRemote.LOB_READ: {
byte[] hmac = transfer.readBytes();
long lobId = transfer.readLong();
byte[] hmac;
CachedInputStream in;
if (clientVersion >= Constants.TCP_PROTOCOL_VERSION_11) {
if (clientVersion >= Constants.TCP_PROTOCOL_VERSION_12) {
hmac = transfer.readBytes();
transfer.verifyLobMac(hmac, lobId);
CachedInputStream in = lobs.get(lobId);
} else {
hmac = null;
}
in = lobs.get(lobId);
if (in == null) {
in = new CachedInputStream(null);
lobs.put(lobId, in);
}
} else {
hmac = null;
in = lobs.get(lobId);
if (in == null) {
throw DbException.get(ErrorCode.OBJECT_CLOSED);
}
}
long offset = transfer.readLong();
if (in.getPos() != offset) {
LobStorage lobStorage = session.getDataHandler().getLobStorage();
......@@ -438,13 +456,30 @@ public class TcpServerThread implements Runnable {
transfer.writeBoolean(true);
Value[] v = result.currentRow();
for (int i = 0; i < result.getVisibleColumnCount(); i++) {
if (clientVersion >= Constants.TCP_PROTOCOL_VERSION_12) {
transfer.writeValue(v[i]);
} else {
writeValue(v[i]);
}
}
} else {
transfer.writeBoolean(false);
}
}
private void writeValue(Value v) throws IOException {
if (v.getType() == Value.CLOB || v.getType() == Value.BLOB) {
if (v instanceof ValueLobDb) {
ValueLobDb lob = (ValueLobDb) v;
if (lob.isStored()) {
long id = lob.getLobId();
lobs.put(id, new CachedInputStream(null));
}
}
}
transfer.writeValue(v);
}
void setThread(Thread thread) {
this.thread = thread;
}
......
......@@ -21,6 +21,7 @@ import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.Arrays;
import org.h2.constant.ErrorCode;
import org.h2.engine.Constants;
import org.h2.engine.SessionInterface;
......@@ -409,14 +410,16 @@ public class Transfer {
writeString(v.getString());
break;
case Value.BLOB: {
if (version >= Constants.TCP_PROTOCOL_VERSION_12) {
if (version >= Constants.TCP_PROTOCOL_VERSION_11) {
if (v instanceof ValueLobDb) {
ValueLobDb lob = (ValueLobDb) v;
if (lob.isStored()) {
writeLong(-1);
writeInt(lob.getTableId());
writeLong(lob.getLobId());
if (version >= Constants.TCP_PROTOCOL_VERSION_12) {
writeBytes(calculateLobMac(lob.getLobId()));
}
writeLong(lob.getPrecision());
break;
}
......@@ -435,14 +438,16 @@ public class Transfer {
break;
}
case Value.CLOB: {
if (version >= Constants.TCP_PROTOCOL_VERSION_12) {
if (version >= Constants.TCP_PROTOCOL_VERSION_11) {
if (v instanceof ValueLobDb) {
ValueLobDb lob = (ValueLobDb) v;
if (lob.isStored()) {
writeLong(-1);
writeInt(lob.getTableId());
writeBytes(calculateLobMac(lob.getLobId()));
writeLong(lob.getLobId());
if (version >= Constants.TCP_PROTOCOL_VERSION_12) {
writeBytes(calculateLobMac(lob.getLobId()));
}
writeLong(lob.getPrecision());
break;
}
......@@ -573,11 +578,16 @@ public class Transfer {
return ValueStringFixed.get(readString());
case Value.BLOB: {
long length = readLong();
if (version >= Constants.TCP_PROTOCOL_VERSION_12) {
if (version >= Constants.TCP_PROTOCOL_VERSION_11) {
if (length == -1) {
int tableId = readInt();
long id = readLong();
byte[] hmac = readBytes();
byte[] hmac;
if (version >= Constants.TCP_PROTOCOL_VERSION_12) {
hmac = readBytes();
} else {
hmac = null;
}
long precision = readLong();
return ValueLobDb.create(Value.BLOB, session.getDataHandler().getLobStorage(), tableId, id, hmac, precision);
}
......@@ -599,11 +609,16 @@ public class Transfer {
}
case Value.CLOB: {
long length = readLong();
if (version >= Constants.TCP_PROTOCOL_VERSION_12) {
if (version >= Constants.TCP_PROTOCOL_VERSION_11) {
if (length == -1) {
int tableId = readInt();
long id = readLong();
byte[] hmac = readBytes();
byte[] hmac;
if (version >= Constants.TCP_PROTOCOL_VERSION_12) {
hmac = readBytes();
} else {
hmac = null;
}
long precision = readLong();
return ValueLobDb.create(Value.CLOB, session.getDataHandler().getLobStorage(), tableId, id, hmac, precision);
}
......@@ -712,11 +727,13 @@ public class Transfer {
}
/**
* Verify the HMAC.
*
* @throws DbException if the HMAC does not verify
*/
public void verifyLobMac(byte[] hmacData, long lobId) {
byte[] result = calculateLobMac(lobId);
if (!result.equals(hmacData)) {
if (!Arrays.equals(result, hmacData)) {
throw DbException.get(ErrorCode.REMOTE_CONNECTION_NOT_ALLOWED);
}
}
......@@ -725,23 +742,10 @@ public class Transfer {
if (lobMacSalt == null) {
lobMacSalt = MathUtils.secureRandomBytes(LOB_MAC_SALT_LENGTH);
}
byte[] hmacData = SHA256.getHashWithSalt(longToBytes(lobId), lobMacSalt);
return hmacData;
}
private static byte[] longToBytes(long src) {
byte[] data = new byte[8];
data[0] = (byte) (src >> 56);
data[1] = (byte) (src >> 48);
data[2] = (byte) (src >> 40);
data[3] = (byte) (src >> 32);
data[4] = (byte) (src >> 24);
data[5] = (byte) (src >> 16);
data[6] = (byte) (src >> 8);
data[7] = (byte) src;
return data;
Utils.writeLong(data, 0, lobId);
byte[] hmacData = SHA256.getHashWithSalt(data, lobMacSalt);
return hmacData;
}
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论