如何使用PHP安全地将JSON数据写入文件

16

我有一个用于编辑图片的HTML表单,所有数据都存储在JSON中。当我更改当前图像时,我希望通过PHP脚本将更改保存到文本文件中。如果我返回到以前的图像,则此配置将再次从该文件发送到表单。

我的问题是:

如何安全地编写/读取这种数据,以及在哪里和如何有效地检查数据以防止一些JS/PHP代码注入?

下面附带了一些概念代码:

JavaScript(使用jQuery):

// Writing
$.ajax({
    global: false,
    type: "POST",
    cache: false,
    dataType: "json",
    data: ({
        action: 'write',
        config: JavaScriptJSON_Obj
    }),
    url: 'read-write.php'
});

// Reading
$.ajax({
    global: false,
    type: "POST",
    cache: false,
    dataType: "json",
    data: ({
        action: 'read'
    }),
    url: 'read-write.php',
    success: function(data){
        JavaScriptJSON_Obj = data;
    }
});

PHP示例(read-write.php):

switch ($_REQUEST['action']) {
    case 'write':
        file_put_contents('config.txt', $_REQUEST['config']);
        break;
    case 'read':
        $s = file_get_contents('config.txt');
        echo json_encode($s);
        break;
}

取决于对 JavascriptJSON_Obj 进行的操作,我想说这可能会为潜在的远程文件包含打开大门。 - inquam
1
只需将其保存为文本数据,然后作为文本数据加载即可。没有任何不安全的因素。您唯一需要考虑的是访问权限。您应该将此信息存储在不直接通过浏览器访问的目录中(这就是为什么您有“read-write.php”用于读取“config.txt”的原因)。您还可以考虑将此数据存储在数据库中。 - binaryLV
3个回答

7

您的代码问题在于它无法工作,安全问题暂且不提。您必须在将数据存储到文件中之前,对其进行序列化或编码为json格式,例如:

switch ($_REQUEST['action']) {
    case 'write':
        file_put_contents('config.txt', json_encode($_REQUEST['config']));
        break;
    case 'read':
        readfile('config.txt');
        break;
}

序列化的工作原理如下:

序列化的工作方式如下:

switch ($_REQUEST['action']) {
    case 'write':
        file_put_contents('config.txt', serialize($_REQUEST['config']));
        break;
    case 'read':
        $data = unserialize(file_get_contents('config.txt'));
        echo json_encode($data);
        break;
}

只要确保读写的路径正确,这段代码就不会出现代码注入问题。唯一可能存在的问题是,如果你可以选择使用哪个文件(而不是将“config.txt”硬编码到代码中),那么你需要验证文件是否在给定的目录中等。

1
@Jacob,感谢您指出这一点。在我的情况下,不需要序列化。我只会存储简单的数据,如文本和数字。 - Max Barnas
哦,那我误解了。我以为 JavaScriptJSON_Obj 是一个任意 JavaScript 对象或数组的占位符。 - Jakob Egger
实际上,在我的JS脚本中,JavaScriptJSON_Obj是一个对象,但仅仅是为了方便。 - Max Barnas

6

首先:JSON不是JavaScript,反之亦然。而且JSON甚至不是JavaScript的一个合适子集。

除此之外,既然你既不将某些用户输入解释为PHP,也不将某些输出解释为JavaScript,那就没必要担心了。但不要忘记正确地指定你的输出:

header('Content-Type: application/json;charset=utf-8');
$s = file_get_contents('config.txt');
echo json_encode($s);

4
我从未说过 JSON 就是 JavaScript,我知道它们的区别。这就好比说 PHP 就是一个数组一样。 - Max Barnas
1
嗯,在某些情况下可能存在潜在的不安全性。例如,数据可能会被存储到一个名为 $_SERVER['DOCUMENT_ROOT'] . '/data.php' 的文件中,该文件可以通过访问 http://example.com/data.php 来执行。但是,用户必须知道文件的名称,并且该文件必须能够被服务器执行(通常不会对.txt文件进行执行)。 - binaryLV

0

我会始终检查所返回的数据是否符合我预期的格式。比如说你正在保存一张图片... 使用 MIME 检查等方式来确保它是一张图片。如果你只是将数据原样保存在服务器上,可能会为一些潜在的安全问题打开大门。

如果你的意思是只保存有关已查看的图片的数据,那么根据数据被访问和使用的方式以及位置,仍然可能存在问题。因此,如果你希望只接收一个整数,确保所接收和保存的数据只是一个整数,而不多余其他内容。


据我所知,检查MIME与不检查一样不安全。如果您想确保“image”确实是图像,应检查数据的结构,而不是表示文件名扩展名的某些文本信息。 - binaryLV
不,当然不是... MIME 只是第一步检查。如果它关闭了,那显然不是图像。但是你可以尝试加载图像以确保它是有效的图像。 - inquam
OP 正在尝试存储 JSON 数据,而不是图像或整数。 - Jakob Egger
1
在JSON对象中存储二进制图像是否真的可行? - Jakob Egger
еҘҪзҡ„пјҢдҪ еҸҜд»ҘдҪҝз”ЁBASE64зј–з Ғд»ҘеҸҠе…¶д»–еҮ з§Қж–№жі•пјҢиҝҷйҮҢжҸҗеҲ°дәҶпјҡhttps://dev59.com/questions/vHM_5IYBdhLWcg3wSBAU - inquam
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接