我已经阅读了一些关于C ++中printf()的安全性的文章。
可以找到例子,例如here。
它让我想知道来自golang的fmt.Printf()
是否安全。
如果格式化的字符串本身可以伪造,则更具体。
inputString := "String from user"
x := "test"
fmt.Printf(inputString, x, 15)
当尝试从C ++复制漏洞时,golang似乎并不容易受到攻击。
E.g。 fmt.Printf("%s%s%s%s%s%s%s%s%s%s%s%s\n")
不会使golang中的程序崩溃。
这样的分析当然不能证明这在golang中是安全的。所以我想在这里问一下:让开发人员对其printf函数进行万无一失的修饰吗?
编辑:通过万无一失,我的意思是它没有任何意想不到的副作用。 我希望结果字符串当然会完全受到损害。 我不希望用户能够获得特权信息(例如未传递给printf的变量的内容),或者用户能够写入任何内存(例如,为x分配新值)。
答案 0 :(得分:1)
C / C ++中的许多内存问题都与空终止和缓冲区溢出有关。 Golang缺乏这两者。字符串是托管资源。在编译器错误的情况下,不可能以逃逸到堆栈的方式终止字符串。
以你的例子为例。由于函数的可变特性,拥有大量没有处理程序的输入处理程序不会影响代码。就printf而言,格式字符串不需要替换。由于你不能传递任何破坏性的东西,即使你的例子为'a ... interface {}'采用动态值,你也会受到编译器的字符串保护代码的保护。
答案 1 :(得分:0)
tl;dr:不要打印不受信任的数据,首先将其转义。如果有疑问或着急,use %q instead of %s。
Go 的字符串格式化方法确实是内存安全的,并且您担心的特定类别的漏洞以及在 C 中如此普遍的漏洞并不适用。
然而,在任何语言中,如果不仔细考虑,通过任何方式输出不受信任的、未经消毒的输入通常都是不安全的。一个众所周知的例子是 cross-site scripting。然而,比 XSS 攻击鲜为人知的是终端 escape 序列 attacks。
常见的终端会响应各种各样的转义序列,这些转义序列可能会直接做一些令人讨厌的事情,或者帮助利用另一个漏洞。攻击者可以将这些序列包含在发送到目标系统的消息中 - 例如,在对网络服务器的请求的 URL 中 - 并等待管理员cat
查看日志或类似内容。这也可用于隐藏信息 - 包括退格序列有效地隐藏了终端中之前出现的任何内容。
最快的选择是简单地使用 %q
instead of %s
。这将字符串输出为 Go 字符串文字,适合在 Go 源代码中使用。这对于打印来说既方便又安全,但如果您尝试匹配特定格式,则可能并不理想。 (strconv.Quote(s string) string
也会直接执行相同的操作)。
This answer to another question 有一个使用 strings.Map 的更复杂但更容易定制的选项,但是在给定的形式中,它删除所有不可打印的字符,而不是转义它们。 >
以某种方式净化您的输出。以后你会为某人省下很多痛苦,可能是你自己。
package main
import (
"fmt"
"strconv"
)
func main() {
s := "a string with some control\x08\x08\x08\x08\x08\x08\x08hidden characters"
// Prints with the control characters intact. Terminal output:
// a string with some hidden characters
fmt.Printf("%s\n", s)
// Prints as Go string literal. Terminal output:
// "a string with some control\b\b\b\b\b\b\bhidden characters"
fmt.Printf("%q\n", s)
// Prints as Go string literal, but without surrounding double-quotes.
// Terminal output:
// a string with some control\b\b\b\b\b\b\bhidden characters
x := strconv.Quote(s)
fmt.Printf("%s\n", x[1:len(x)-1])
}