Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion hugegraph-server/hugegraph-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
<jraft.version>1.3.11</jraft.version>
<ohc.version>0.7.4</ohc.version>
<jna.version>5.12.1</jna.version>
<lz4.version>1.8.0</lz4.version>
<lz4.version>1.8.1</lz4.version>
<mmseg4j-core.version>1.10.0</mmseg4j-core.version>
<jcseg.version>2.6.2</jcseg.version>
<hanlp.version>portable-1.8.3</hanlp.version>
Expand Down Expand Up @@ -197,6 +197,8 @@
<artifactId>commons-compress</artifactId>
<version>${commons-compress.version}</version>
</dependency>
<!-- LZ4 version update from 1.8.0 to 1.8.1. For details on the specific changes, please refer to:
https://sites.google.com/sonatype.com/vulnerabilities/cve-2025-12183 -->
<dependency>
<groupId>org.lz4</groupId>
<artifactId>lz4-java</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,7 @@ public HugeUser matchUser(String name, String password) {
}

if (StringEncoding.checkPassword(password, user.password())) {
// TODO: rehash password if bcrypt work factor is lower than expected
this.pwdCache.update(user.id(), password);
return user;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -947,6 +947,7 @@ public HugeUser matchUser(String name, String password) {
}

if (StringEncoding.checkPassword(password, user.password())) {
// TODO: rehash password if bcrypt work factor is lower than expected
this.pwdCache.update(user.id(), password);
return user;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,15 +160,26 @@ public static void decompressTar(String sourceFile, String outputDir,

private static Path zipSlipProtect(ArchiveEntry entry, Path targetDir)
throws IOException {
Path targetDirResolved = targetDir.resolve(entry.getName());
return zipSlipProtect(entry.getName(), targetDir);
}

private static Path zipSlipProtect(ZipEntry entry, Path targetDir)
throws IOException {
return zipSlipProtect(entry.getName(), targetDir);
}

private static Path zipSlipProtect(String entryName, Path targetDir)
throws IOException {

Path targetDirResolved = targetDir.resolve(entryName);

/*
* Make sure normalized file still has targetDir as its prefix,
* else throws exception
*/
Path normalizePath = targetDirResolved.normalize();
if (!normalizePath.startsWith(targetDir.normalize())) {
throw new IOException(String.format("Bad entry: %s",
entry.getName()));
throw new IOException(String.format("Bad entry: %s", entryName));
}
return normalizePath;
}
Expand Down Expand Up @@ -220,9 +231,8 @@ public static void decompressZip(String sourceFile, String outputDir,
ZipInputStream zis = new ZipInputStream(bis)) {
ZipEntry entry;
while ((entry = zis.getNextEntry()) != null) {
String fileName = entry.getName();
File entryFile = new File(Paths.get(outputDir, fileName)
.toString());
Path entryPath = zipSlipProtect(entry, Paths.get(outputDir));
File entryFile = new File(entryPath.toString());
FileUtils.forceMkdir(entryFile.getParentFile());
try (FileOutputStream fos = new FileOutputStream(entryFile);
BufferedOutputStream bos = new BufferedOutputStream(fos)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public final class StringEncoding {
private static final byte[] BYTES_EMPTY = new byte[0];
private static final String STRING_EMPTY = "";
private static final int BLOCK_SIZE = 4096;
private static final int BCRYPT_WORK_FACTOR = 10;

static {
final String ALG = "SHA-256";
Expand Down Expand Up @@ -140,7 +141,9 @@ public static String decompress(byte[] value, float bufferRatio) {
}

public static String hashPassword(String password) {
return BCrypt.hashpw(password, BCrypt.gensalt(4));
// OWASP suggests 10 as a minimum and 12–14 for production;
// workFactor 12 is not used by default due to its 200+ ms cost.
return BCrypt.hashpw(password, BCrypt.gensalt(BCRYPT_WORK_FACTOR));
}

public static boolean checkPassword(String candidatePassword, String dbPassword) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.apache.hugegraph.util.Bytes;
import org.apache.hugegraph.util.StringEncoding;
import org.junit.Test;
import org.mindrot.jbcrypt.BCrypt;

public class StringEncodingTest {

Expand Down Expand Up @@ -180,4 +181,41 @@ public void testReadAsciiString() {
buf = Bytes.fromHex("80");
Assert.assertEquals("", StringEncoding.readAsciiString(buf, 0));
}

@Test
public void testCheckPasswordSupportsOldAndNewCost() {
String testPassword = "test123!@#";

// Test old work factor (4)
String oldPassword = BCrypt.hashpw(testPassword, BCrypt.gensalt(4));
Assert.assertTrue(StringEncoding.checkPassword(testPassword, oldPassword));
Assert.assertFalse(StringEncoding.checkPassword("wrong", oldPassword));

// Test new work factor (10)
String newPassword = BCrypt.hashpw(testPassword, BCrypt.gensalt(10));
Assert.assertTrue(StringEncoding.checkPassword(testPassword, newPassword));
Assert.assertFalse(StringEncoding.checkPassword("wrong", newPassword));

// Test that hashPassword uses the new cost factor
String hashedPassword = StringEncoding.hashPassword(testPassword);
Assert.assertTrue("Hash should contain work factor 10",
hashedPassword.matches("^\\$2[aby]\\$10\\$.*")
);

// Compare computational cost between work factor 4 and 10
long start4 = System.nanoTime();
StringEncoding.checkPassword(testPassword, oldPassword);
long elapsed4 = System.nanoTime() - start4;

long start10 = System.nanoTime();
StringEncoding.checkPassword(testPassword, hashedPassword);
long elapsed10 = System.nanoTime() - start10;

// BCrypt cost difference: (10-4) = 6 => theoretical ~2^6 = 64x
Assert.assertTrue(
"Work factor 10 should be significantly slower than work factor 4 " +
"(expected exponential cost increase)",
elapsed10 >= elapsed4 * 32
);
}
}
4 changes: 3 additions & 1 deletion hugegraph-struct/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,12 @@
<artifactId>fastutil</artifactId>
<version>8.1.0</version>
</dependency>
<!-- LZ4 version update from 1.7.1 to 1.8.1. For details on the specific changes, please refer to:
https://sites.google.com/sonatype.com/vulnerabilities/cve-2025-12183 -->
<dependency>
<groupId>org.lz4</groupId>
<artifactId>lz4-java</artifactId>
<version>1.7.1</version>
<version>1.8.1</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ public final class StringEncoding {
private static final byte[] BYTES_EMPTY = new byte[0];
private static final int BLOCK_SIZE = 4096;

private static final int BCRYPT_WORK_FACTOR = 10;

static {
final String ALG = "SHA-256";
try {
Expand Down Expand Up @@ -165,7 +167,9 @@ public static String decompress(byte[] value, float bufferRatio) {
}

public static String hashPassword(String password) {
return BCrypt.hashpw(password, BCrypt.gensalt(4));
// OWASP suggests 10 as a minimum and 12–14 for production;
// workFactor 12 is not used by default due to its 200+ ms cost.
return BCrypt.hashpw(password, BCrypt.gensalt(BCRYPT_WORK_FACTOR));
}

public static boolean checkPassword(String candidatePassword,
Expand Down
3 changes: 1 addition & 2 deletions install-dist/release-docs/LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -649,8 +649,7 @@ The text of each license is also included in licenses/LICENSE-[project].txt.
https://central.sonatype.com/artifact/org.lionsoul/jcseg-core/2.2.0 -> Apache 2.0
https://central.sonatype.com/artifact/org.lionsoul/jcseg-core/2.6.2 -> Apache 2.0
https://central.sonatype.com/artifact/org.lz4/lz4-java/1.4.0 -> Apache 2.0
https://central.sonatype.com/artifact/org.lz4/lz4-java/1.7.1 -> Apache 2.0
https://central.sonatype.com/artifact/org.lz4/lz4-java/1.8.0 -> Apache 2.0
https://central.sonatype.com/artifact/org.lz4/lz4-java/1.8.1 -> Apache 2.0
https://central.sonatype.com/artifact/org.nlpcn/nlp-lang/1.7.7 -> Apache 2.0
https://central.sonatype.com/artifact/org.objenesis/objenesis/2.6 -> Apache 2.0
https://central.sonatype.com/artifact/org.objenesis/objenesis/3.2 -> Apache 2.0
Expand Down
202 changes: 0 additions & 202 deletions install-dist/release-docs/licenses/LICENSE-lz4-java-1.8.0.txt

This file was deleted.

Loading
Loading