mirror of
https://github.com/corda/corda.git
synced 2025-06-18 23:28:21 +00:00
Improve attachment checks to ensure that a stream is actually a JAR/ZIP.
This commit is contained in:
@ -21,7 +21,9 @@ import net.corda.node.services.persistence.schemas.Models
|
|||||||
import java.io.ByteArrayInputStream
|
import java.io.ByteArrayInputStream
|
||||||
import java.io.FilterInputStream
|
import java.io.FilterInputStream
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.nio.file.*
|
import java.nio.file.FileAlreadyExistsException
|
||||||
|
import java.nio.file.Path
|
||||||
|
import java.nio.file.Paths
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.jar.JarInputStream
|
import java.util.jar.JarInputStream
|
||||||
import javax.annotation.concurrent.ThreadSafe
|
import javax.annotation.concurrent.ThreadSafe
|
||||||
@ -159,14 +161,21 @@ class NodeAttachmentService(override var storePath: Path, dataSourceProperties:
|
|||||||
|
|
||||||
private fun checkIsAValidJAR(stream: InputStream) {
|
private fun checkIsAValidJAR(stream: InputStream) {
|
||||||
// Just iterate over the entries with verification enabled: should be good enough to catch mistakes.
|
// Just iterate over the entries with verification enabled: should be good enough to catch mistakes.
|
||||||
|
// Note that JarInputStream won't throw any kind of error at all if the file stream is in fact not
|
||||||
|
// a ZIP! It'll just pretend it's an empty archive, which is kind of stupid but that's how it works.
|
||||||
|
// So we have to check to ensure we found at least one item.
|
||||||
val jar = JarInputStream(stream)
|
val jar = JarInputStream(stream)
|
||||||
|
var count = 0
|
||||||
while (true) {
|
while (true) {
|
||||||
val cursor = jar.nextJarEntry ?: break
|
val cursor = jar.nextJarEntry ?: break
|
||||||
val entryPath = Paths.get(cursor.name)
|
val entryPath = Paths.get(cursor.name)
|
||||||
// Security check to stop zips trying to escape their rightful place.
|
// Security check to stop zips trying to escape their rightful place.
|
||||||
if (entryPath.isAbsolute || entryPath.normalize() != entryPath || '\\' in cursor.name)
|
if (entryPath.isAbsolute || entryPath.normalize() != entryPath || '\\' in cursor.name || cursor.name == "." || cursor.name == "..")
|
||||||
throw IllegalArgumentException("Path is either absolute or non-normalised: $entryPath")
|
throw IllegalArgumentException("Path is either absolute or non-normalised: $entryPath")
|
||||||
|
count++
|
||||||
}
|
}
|
||||||
|
if (count == 0)
|
||||||
|
throw IllegalArgumentException("Stream is either empty or not a JAR/ZIP")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implementations for AcceptsFileUpload
|
// Implementations for AcceptsFileUpload
|
||||||
|
@ -9,6 +9,7 @@ import net.corda.core.read
|
|||||||
import net.corda.core.readAll
|
import net.corda.core.readAll
|
||||||
import net.corda.core.utilities.LogHelper
|
import net.corda.core.utilities.LogHelper
|
||||||
import net.corda.core.write
|
import net.corda.core.write
|
||||||
|
import net.corda.core.writeLines
|
||||||
import net.corda.node.services.database.RequeryConfiguration
|
import net.corda.node.services.database.RequeryConfiguration
|
||||||
import net.corda.node.services.persistence.NodeAttachmentService
|
import net.corda.node.services.persistence.NodeAttachmentService
|
||||||
import net.corda.node.services.persistence.schemas.AttachmentEntity
|
import net.corda.node.services.persistence.schemas.AttachmentEntity
|
||||||
@ -86,7 +87,6 @@ class NodeAttachmentStorageTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `duplicates not allowed`() {
|
fun `duplicates not allowed`() {
|
||||||
|
|
||||||
val testJar = makeTestJar()
|
val testJar = makeTestJar()
|
||||||
val storage = NodeAttachmentService(fs.getPath("/"), dataSourceProperties, MetricRegistry())
|
val storage = NodeAttachmentService(fs.getPath("/"), dataSourceProperties, MetricRegistry())
|
||||||
testJar.read {
|
testJar.read {
|
||||||
@ -126,6 +126,14 @@ class NodeAttachmentStorageTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException::class)
|
||||||
|
fun `non jar rejected`() {
|
||||||
|
val storage = NodeAttachmentService(fs.getPath("/"), dataSourceProperties, MetricRegistry())
|
||||||
|
val path = fs.getPath("notajar")
|
||||||
|
path.writeLines(listOf("Hey", "there!"))
|
||||||
|
path.read { storage.importAttachment(it) }
|
||||||
|
}
|
||||||
|
|
||||||
private var counter = 0
|
private var counter = 0
|
||||||
private fun makeTestJar(): Path {
|
private fun makeTestJar(): Path {
|
||||||
counter++
|
counter++
|
||||||
|
Reference in New Issue
Block a user