我有一个脚本,可以将变量存储在.txt文件中供以后使用。我想安全地从文件中检索这些变量。
我现在如何设置:
SETTINGS.TXT
var1=value1
var2=value2
...
脚本
for i in $(cat Settings.txt); do $i done
# So now "var1" has the value "value1", and so on
这很有效,但是很危险,因为有人可以通过该txt文件注入代码。
我知道source
命令,但也有同样的问题。那么,如何安全地实现相同的功能呢?
答案 0 :(得分:3)
如果您不想要单独的步骤进行验证和变量创建:
更新,基于package com.example.enan.checkinternetconnection;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "";
private static final String LOG_TAG = "";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
}
public boolean hasActiveInternetConnection(Context context) {
if (isNetworkAvailable(context)) {
try {
HttpURLConnection urlc = (HttpURLConnection) (new URL("http://www.google.com").openConnection());
urlc.setRequestProperty("User-Agent", "Test");
urlc.setRequestProperty("Connection", "close");
urlc.setConnectTimeout(1500);
urlc.connect();
return (urlc.getResponseCode() == 200);
} catch (IOException e) {
Log.e(LOG_TAG, "Error checking internet connection", e);
}
} else {
Log.d(LOG_TAG, "No network available!");
}
return false;
}
public boolean isNetworkAvailable(Context context) {
ConnectivityManager connectivityManager
= (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
return activeNetworkInfo != null;
}
}
:更安全的更简单方法是使用declare
内置来定义变量:
declare
#!/usr/bin/env bash
# Read the file line by line.
while read -r line; do
declare -- "$line"
done <<'EOF'
var1=value1
var2=value2
EOF
命令失败,输入行不是有效的shell变量赋值,但安全失败,因为该行永远不会被评估为命令
请注意,这些值将被视为 literals ,与文件中定义的完全相同(删除尾随空格除外)。
如果您还想支持单引号或双引号值,请改用以下declare
命令:
declare
但请注意,在值中使用相同类型的嵌入式转义引号不支持(这是declare -- "$(xargs -I {} printf %s {} <<<"$line")"
的限制)。
原始答案,基于xargs
:
printf -v
请注意,这些值将被读取为 literals ,与文件中定义的完全相同(删除尾随空格除外)。
#!/usr/bin/env bash
# Read the file line by line.
while read -r line; do
# Split the line into name and value using regex matching.
if [[ $line =~ ^([^=]+)=(.*)$ ]]; then
# ${BASH_REMATCH[1]} now contains the variable name,
# ${BASH_REMATCH[2]} the value.
# Use printf -v to store the value in a variable.
printf -v "${BASH_REMATCH[1]}" %s "${BASH_REMATCH[2]}"
fi
done <<'EOF'
var1=value1
var2=value2
EOF
# Print the variables that were created (based on name prefix `var`).
for name in ${!var*}; do
printf '%s=%s\n' "$name" "${!name}"
done
命令:printf -v
应该可以安全使用,因为printf -v "${BASH_REMATCH[1]}" %s "$(xargs -I {} printf %s {} <<<"${BASH_REMATCH[2]}")"
用于创建变量 - shell不会直接获取赋值语句,这是注入可能发生的地方。
简单地跳过未被识别为变量赋值的行。
正则表达式printf -v
匹配以(^([^=]+)=(.*)$
)开头的任何行,除了^
(+
)以外的至少1(=
)个字符,直接跟[^=]
,后跟任意剩余的字符序列(=
)到行尾(.*
)。 $
和([^=]+)
周围的括号可确保捕获的子字符串保存在特殊的Bash数组变量(.*)
中,从索引1开始。
${BASH_REMATCH[@]}
命令可能会在以后失败。答案 1 :(得分:1)
您可以在采购前检查变量分配格式:
#!/bin/bash
file=Settings.txt
regex_varname='^[a-zA-Z0-9_]\+\'
regex_varvalue='[a-zA-Z0-9]\+$'
is_safe_var() {
while read var; do
grep -q $regex_varname=$regex_varvalue <<< "$var" || return 1
done < "$file"
}
is_safe_var && source "$file" || echo "Break"
变量$regex_varname
和$regex_varvalue
被赋予变量授权名称和值的模式:
^[a-zA-Z0-9_]
:以一个或多个字母数字字符开头的变量名称或_
[a-zA-Z0-9]\+$
:以一个或多个字母数字字符结尾的变量值如果变量赋值与模式is_safe_var
匹配,则函数Settings.txt
中的循环会检查$regex_varname=$regex_varvalue
的每一行。
如果一行未通过测试,则会从包含错误代码和echo "Break"
的函数返回,否则将Settings.txt
来源。
注意:您可以使用变量名称和值中的授权字符填写字符范围[a-zA-Z0-9_]
和[a-zA-Z0-9]
。