diff --git a/upload/api/db/dbbak.php b/upload/api/db/dbbak.php
index 3ac052aef8a5064a31b2582a6136a2e56915a409..6885d413ad560e77a2109fe097b7843adbae1c20 100644
--- a/upload/api/db/dbbak.php
+++ b/upload/api/db/dbbak.php
@@ -515,6 +515,10 @@ if($get['method'] == 'export') {
$get['volume'] = 0;
}
+ if(!preg_match('/^backup_(\d+)_\w+$/', $get['sqlpath']) || !preg_match('/^\d+_\w+\-(\d+).sql$/', $get['dumpfile'])) {
+ api_msg('bak_file_lose', $get['dumpfile']);
+ }
+
$get['volume']++;
$next_dumpfile = preg_replace('/^(\d+)\_(\w+)\-(\d+)\.sql$/', '\\1_\\2-'.$get['volume'].'.sql', $get['dumpfile']);
if(!is_file(BACKUP_DIR.$get['sqlpath'].'/'.$get['dumpfile'])) {
@@ -558,7 +562,7 @@ if($get['method'] == 'export') {
$directory = dir(BACKUP_DIR);
while($entry = $directory->read()) {
$filename = BACKUP_DIR.$entry;
- if(is_dir($filename) && preg_match('/backup_(\d+)_\w+$/', $filename, $match)) {
+ if(is_dir($filename) && preg_match('/^backup_(\d+)_\w+$/', $filename, $match)) {
$str .= "\t
\n";
$str .= "\t\t$filename \n";
$str .= "\t\t$match[1] \n";
diff --git a/upload/config/config_global_default.php b/upload/config/config_global_default.php
index 705c233ce454bb2ac5a61015ce310d85869fe884..d5a9bbf494f9bb9511db77b20d6456b4a9b4136a 100644
--- a/upload/config/config_global_default.php
+++ b/upload/config/config_global_default.php
@@ -176,6 +176,7 @@ $_config['admincp']['forcesecques'] = 0; // 管理人员必须设置安全提
$_config['admincp']['checkip'] = 1; // 后台管理操作是否验证管理员的 IP, 1=是[安全], 0=否。仅在管理员无法登陆后台时设置 0。
$_config['admincp']['runquery'] = 0; // 是否允许后台运行 SQL 语句 1=是 0=否[安全]
$_config['admincp']['dbimport'] = 1; // 是否允许后台恢复论坛数据 1=是 0=否[安全]
+$_config['admincp']['mustlogin'] = 1; // 是否必须前台登录后才允许后台登录 1=是[安全] 0=否
/**
* 系统远程调用功能模块
diff --git a/upload/install/include/install_function.php b/upload/install/include/install_function.php
index 6494b450a1d60d9fc8917ecf376a77c57ddbce5c..67c9ab9e4a6437004059b232d057f010270fa5d4 100644
--- a/upload/install/include/install_function.php
+++ b/upload/install/include/install_function.php
@@ -798,17 +798,6 @@ function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
}
-function generate_key() {
- $random = random(32);
- $info = md5($_SERVER['SERVER_SOFTWARE'].$_SERVER['SERVER_NAME'].$_SERVER['SERVER_ADDR'].$_SERVER['SERVER_PORT'].$_SERVER['HTTP_USER_AGENT'].time());
- $return = array();
- for($i=0; $i<64; $i++) {
- $p = intval($i/2);
- $return[$i] = $i % 2 ? $random[$p] : $info[$p];
- }
- return implode('', $return);
-}
-
function show_install() {
if(VIEW_OFF) return;
?>
@@ -1336,14 +1325,14 @@ EOT;
return $success;
}
-function _generate_key() {
- $random = random(32);
+function _generate_key($length = 32) {
+ $random = random($length);
$info = md5($_SERVER['SERVER_SOFTWARE'].$_SERVER['SERVER_NAME'].$_SERVER['SERVER_ADDR'].$_SERVER['SERVER_PORT'].$_SERVER['HTTP_USER_AGENT'].time());
- $return = array();
- for($i=0; $i<32; $i++) {
- $return[$i] = $random[$i].$info[$i];
+ $return = '';
+ for($i=0; $i<$length; $i++) {
+ $return .= $random[$i].$info[$i];
}
- return implode('', $return);
+ return $return;
}
function uc_write_config($config, $file, $password) {
diff --git a/upload/source/admincp/admincp_checktools.php b/upload/source/admincp/admincp_checktools.php
index 58f595dce72e1ff3ea5f8de9dab1828cc738b78b..8fbda7fb89b6c65dc650232449de8d9827fa0cde 100644
--- a/upload/source/admincp/admincp_checktools.php
+++ b/upload/source/admincp/admincp_checktools.php
@@ -286,6 +286,50 @@ if($operation == 'filecheck') {
}
}
+} elseif($operation == 'replacekey') {
+
+ $step = max(1, intval($_GET['step']));
+ shownav('tools', 'nav_replacekey');
+ showtips('replacekey_tips');
+ showsubmenusteps('nav_replacekey', array(
+ array('nav_replacekey_confirm', $step == 1),
+ array('nav_replacekey_verify', $step == 2),
+ array('nav_replacekey_completed', $step == 3)
+ ));
+ if($step == 1) {
+ cpmsg(cplang('replacekey_tips_step1'), 'action=checktools&operation=replacekey&step=2', 'form', '', FALSE);
+ } elseif($step == 2) {
+ cpmsg(cplang('replacekey_tips_step2'), "action=checktools&operation=replacekey&step=3", 'loading', '', FALSE);
+ } elseif($step == 3) {
+ if(!is_writeable('./config/config_global.php')) {
+ cpmsg('replacekey_must_write_config', '', 'error');
+ }
+
+ $oldauthkey = $_G['config']['security']['authkey'];
+ $newauthkey = generate_key(64);
+
+ $configfile = trim(file_get_contents(DISCUZ_ROOT.'./config/config_global.php'));
+ $configfile = substr($configfile, -2) == '?>' ? substr($configfile, 0, -2) : $configfile;
+ $configfile = str_replace($oldauthkey, $newauthkey, $configfile);
+
+ if(file_put_contents(DISCUZ_ROOT.'./config/config_global.php', trim($configfile), LOCK_EX) === false) {
+ cpmsg('replacekey_must_write_config', '', 'error');
+ }
+
+ $ecdata = authcode($_G['setting']['ec_contract'], 'DECODE', $oldauthkey);
+ $ecdata = authcode($ecdata, 'ENCODE', $newauthkey);
+ C::t('common_setting')->update('ec_contract', $ecdata);
+
+ $ftpdata = $_G['setting']['ftp'];
+ $ftppasswd = authcode($ftpdata['password'], 'DECODE', md5($oldauthkey));
+ $ftpdata['password'] = authcode($ftppasswd, 'ENCODE', md5($newauthkey));
+ C::t('common_setting')->update('ftp', $ftpdata);
+
+ updatecache('setting');
+
+ cpmsg('replacekey_succeed', '', 'succeed', '', FALSE);
+ }
+
} elseif($operation == 'ftpcheck') {
$alertmsg = '';
@@ -631,4 +675,13 @@ function findhook($hookid, $key) {
}
$hooks[] = '';
}
-?>
\ No newline at end of file
+
+function generate_key($length = 32) {
+ $random = random($length);
+ $info = md5($_SERVER['SERVER_SOFTWARE'].$_SERVER['SERVER_NAME'].$_SERVER['SERVER_ADDR'].$_SERVER['SERVER_PORT'].$_SERVER['HTTP_USER_AGENT'].time());
+ $return = '';
+ for($i=0; $i<$length; $i++) {
+ $return .= $random[$i].$info[$i];
+ }
+ return $return;
+}
\ No newline at end of file
diff --git a/upload/source/admincp/admincp_index.php b/upload/source/admincp/admincp_index.php
index 8860d3a57622831b0a7bde4c1c9a2ee0e1a70bf5..8ba692ae8e956222a3fb82d08920ab40bad7031b 100644
--- a/upload/source/admincp/admincp_index.php
+++ b/upload/source/admincp/admincp_index.php
@@ -36,6 +36,25 @@ if(empty($siteuniqueid) || strlen($siteuniqueid) < 16) {
updatecache('setting');
}
+if(!empty($_GET['closesitereleasetips'])) {
+ C::t('common_setting')->update('sitereleasetips', 0);
+ $sitereleasetips = 0;
+ require_once libfile('function/cache');
+ updatecache('setting');
+} else {
+ $sitereleasetips = C::t('common_setting')->fetch('sitereleasetips');
+}
+
+$siterelease = C::t('common_setting')->fetch('siterelease');
+$releasehash = substr(hash('sha512', $_G['config']['security']['authkey'].DISCUZ_VERSION.DISCUZ_RELEASE.$siteuniqueid), 0, 32);
+if(empty($siterelease) || strcmp($siterelease, $releasehash) !== 0) {
+ C::t('common_setting')->update('siteversion', DISCUZ_VERSION);
+ C::t('common_setting')->update('siterelease', $releasehash);
+ C::t('common_setting')->update('sitereleasetips', 1);
+ $sitereleasetips = 1;
+ require_once libfile('function/cache');
+ updatecache('setting');
+}
if(submitcheck('notesubmit', 1)) {
if(!empty($_GET['noteid']) && is_numeric($_GET['noteid'])) {
@@ -259,6 +278,14 @@ if ($env_ok) {
}
showtablefooter();
+if($sitereleasetips) {
+ showtableheader('version_tips', 'fixpadding');
+ showtablerow('', array('', 'class="td21" style="text-align:right;"'),
+ ''.lang("admincp", "version_tips_msg", array('ADMINSCRIPT' => ADMINSCRIPT, 'version' => constant("DISCUZ_VERSION").' R'.constant("DISCUZ_RELEASE"))).' '
+ );
+ showtablefooter();
+}
+
showtableheader('home_onlines', 'nobottom fixpadding');
echo ''.$onlines.' ';
showtablefooter();
diff --git a/upload/source/admincp/admincp_login.php b/upload/source/admincp/admincp_login.php
index 90090f5ba18fa5e345b0d24fc256f4fa27569691..fa22f9ac21ca853220ba2d7cab4fe6453e192a02 100644
--- a/upload/source/admincp/admincp_login.php
+++ b/upload/source/admincp/admincp_login.php
@@ -23,7 +23,10 @@ if($this->cpaccess == -3) {
}
-if($this->cpaccess == -3) {
+if(!getglobal('uid') && getglobal('config/admincp/mustlogin')) {
+ echo ''.lang('admincp_login', 'login_cp_guest').'
';
+
+} elseif(!getstatus(getglobal('member/allowadmincp'), 1) || $this->cpaccess == -3) {
echo ''.lang('admincp_login', 'login_cp_noaccess').'
';
diff --git a/upload/source/admincp/admincp_menu.php b/upload/source/admincp/admincp_menu.php
index 561931188938cc47ac59b50d98b1fa7524e84948..3324ceebf7451407a780987d1b0cf0aec84bee43 100644
--- a/upload/source/admincp/admincp_menu.php
+++ b/upload/source/admincp/admincp_menu.php
@@ -243,6 +243,7 @@ $menu['tools'] = array(
$isfounder ? array('menu_tools_fileperms', 'tools_fileperms') : null,
$isfounder ? array('menu_tools_filecheck', 'checktools_filecheck') : null,
$isfounder ? array('menu_tools_hookcheck', 'checktools_hookcheck') : null,
+ $isfounder ? array('menu_tools_replacekey', 'checktools_replacekey') : null,
);
if($isfounder) {
diff --git a/upload/source/admincp/admincp_optimizer.php b/upload/source/admincp/admincp_optimizer.php
index b275323a928d5cbdcf8fe68f78e885183573053c..d2d706bbde669418bf22a50853fc36736f2ecf9e 100644
--- a/upload/source/admincp/admincp_optimizer.php
+++ b/upload/source/admincp/admincp_optimizer.php
@@ -43,6 +43,9 @@ $security_option = array(
'optimizer_plugin',
'optimizer_loginpwcheck',
'optimizer_loginoutofdate',
+ 'optimizer_dbbackup_visit',
+ 'optimizer_filesafe',
+ 'optimizer_remote',
);
$serversec_option = array(
diff --git a/upload/source/class/optimizer/optimizer_dbbackup_visit.php b/upload/source/class/optimizer/optimizer_dbbackup_visit.php
new file mode 100644
index 0000000000000000000000000000000000000000..6f1b7dc38b7f6ac2851fd056f0c66f3520e30951
--- /dev/null
+++ b/upload/source/class/optimizer/optimizer_dbbackup_visit.php
@@ -0,0 +1,102 @@
+check_exportfile($exportlog, $exportziplog, $exportsize, $filecount);
+ if(!$filecount) {
+ $return = array('status' => 0, 'type' => 'none', 'lang' => lang('optimizer', 'optimizer_dbbackup_visit_safe'));
+ } else {
+ $return = array('status' => 1, 'type' => 'notice', 'lang' => lang('optimizer', 'optimizer_dbbackup_visit_delete', array('filecount' => $filecount)));
+ }
+ return $return;
+ }
+
+ function get_backup_dir() {
+
+ $backupdirs = array();
+ $dir = dir(DISCUZ_ROOT.'./data');
+ while(($file = $dir->read()) !== FALSE) {
+ if(filetype(DISCUZ_ROOT.'./data/'.$file) == 'dir' && preg_match('/^backup_\w+/', $file)) {
+ $backupdirs[] = $file;
+ }
+ }
+ $dir->close();
+ return $backupdirs;
+ }
+
+ function check_exportfile(&$exportlog, &$exportziplog, &$exportsize, &$filecount) {
+
+ $backupdirs = $this->get_backup_dir();
+ if(empty($backupdirs)) {
+ return;
+ }
+
+ $filecount = 0;
+ foreach($backupdirs as $backupdir) {
+ $dir = dir(DISCUZ_ROOT.'./data/'.$backupdir);
+ while($entry = $dir->read()) {
+ $entry = './data/'.$backupdir.'/'.$entry;
+ if(is_file($entry)) {
+ if(preg_match("/\.sql$/i", $entry)) {
+ $filesize = filesize($entry);
+ $fp = fopen($entry, 'rb');
+ $identify = explode(',', base64_decode(preg_replace("/^# Identify:\s*(\w+).*/s", "\\1", fgets($fp, 256))));
+ fclose($fp);
+ $key = preg_replace('/^(.+?)(\-\d+)\.sql$/i', '\\1', basename($entry));
+ $exportlog[$key][$identify[4]] = array(
+ 'version' => $identify[1],
+ 'type' => $identify[2],
+ 'method' => $identify[3],
+ 'volume' => $identify[4],
+ 'tablepre' => $identify[5],
+ 'dbcharset' => $identify[6],
+ 'filename' => $entry,
+ 'dateline' => filemtime($entry),
+ 'size' => $filesize
+ );
+ $testurl = str_replace('./data/', getglobal('siteurl').'data/', $entry);
+ $content = dfsockopen($testurl);
+ if(!empty($content)) {
+ $filecount++;
+ $exportsize[$key] += $filesize;
+ }
+ } elseif(preg_match("/\.zip$/i", $entry)) {
+ $key = preg_replace('/^(.+?)(\-\d+)\.zip$/i', '\\1', basename($entry));
+ $filesize = filesize($entry);
+ $exportziplog[$key][] = array(
+ 'type' => 'zip',
+ 'filename' => $entry,
+ 'size' => filesize($entry),
+ 'dateline' => filemtime($entry)
+ );
+ $testurl = str_replace('./data/', getglobal('siteurl').'data/', $entry);
+ $content = dfsockopen($testurl);
+ if(!empty($content)) {
+ $filecount++;
+ }
+ }
+ }
+ }
+ $dir->close();
+ }
+ }
+}
\ No newline at end of file
diff --git a/upload/source/class/optimizer/optimizer_filesafe.php b/upload/source/class/optimizer/optimizer_filesafe.php
new file mode 100644
index 0000000000000000000000000000000000000000..7a76f8c9fbb667afcfa2f2eee83118f125a66ed6
--- /dev/null
+++ b/upload/source/class/optimizer/optimizer_filesafe.php
@@ -0,0 +1,46 @@
+ 1, 'type' =>'header', 'lang' => lang('optimizer', 'optimizer_filesafe_need'));
+ } else {
+ $return = array('status' => 0, 'type' =>'none', 'lang' => lang('optimizer', 'optimizer_filesafe_no_need'));
+ }
+ return $return;
+ }
+
+ public function optimizer() {
+ @unlink(DISCUZ_ROOT.'/install/index.php');
+ @unlink(DISCUZ_ROOT.'/uc_server/install/index.php');
+ @unlink(DISCUZ_ROOT.'/ucenter/install/index.php');
+ @unlink(DISCUZ_ROOT.'/data/restore.php');
+ if(strcmp(ADMINSCRIPT, 'admin.php') !== 0 && file_exists(DISCUZ_ROOT.'/admin.php')) {
+ @unlink(DISCUZ_ROOT.'/admin.php');
+ }
+ cpmsg('optimizer_filesafe_optimizer', '', 'error');
+ }
+}
\ No newline at end of file
diff --git a/upload/source/class/optimizer/optimizer_remote.php b/upload/source/class/optimizer/optimizer_remote.php
new file mode 100644
index 0000000000000000000000000000000000000000..a894636e396e71d2ecf11d26c82ae75709f3834b
--- /dev/null
+++ b/upload/source/class/optimizer/optimizer_remote.php
@@ -0,0 +1,33 @@
+ 1, 'type' =>'header', 'lang' => lang('optimizer', 'optimizer_remote_need'));
+ } else {
+ $return = array('status' => 0, 'type' =>'none', 'lang' => lang('optimizer', 'optimizer_remote_no_need'));
+ }
+ return $return;
+ }
+
+ public function optimizer() {
+ cpmsg('optimizer_remote_optimizer', '', 'error');
+ }
+}
\ No newline at end of file
diff --git a/upload/source/language/lang_admincp.php b/upload/source/language/lang_admincp.php
index 3541adc2b2e52debeaeff02393759628e229316a..14854f5710f9743502dc59a07740101b4c9174d9 100644
--- a/upload/source/language/lang_admincp.php
+++ b/upload/source/language/lang_admincp.php
@@ -505,6 +505,11 @@ $lang = array
'nav_hookcheck_verify' => '开始校验',
'nav_hookcheck_completed' => '校验结果',
+ 'nav_replacekey' => '密钥更新',
+ 'nav_replacekey_confirm' => '确认开始',
+ 'nav_replacekey_verify' => '开始更新',
+ 'nav_replacekey_completed' => '更新结果',
+
'nav_updatecache' => '更新缓存',
'nav_updatecache_confirm' => '确认开始',
'nav_updatecache_verify' => '开始更新',
@@ -5992,6 +5997,10 @@ $lang = array
'hookcheck_discuzhook' => '源文件嵌入点',
'hookcheck_delhook' => '丢失的嵌入点',
+ 'replacekey_tips' => '当站点沦陷时您应该考虑在此处密钥更新,以避免黑客通过已知的 AUTHKEY 获取站点控制权限。 少数插件会使用站点密钥保存数据,当重置密钥时相关数据会丢失且无法恢复,敬请注意并在更新前做好数据库与站点文件的备份工作。 ',
+ 'replacekey_tips_step1' => '在操作之前建议您选择低峰期操作或临时关闭下挂网站,并做好数据、文件备份工作,点击下面按钮开始更换',
+ 'replacekey_tips_step2' => '正在进行密钥更新,请稍候......',
+
'imagepreview_imagesize_source' => '原图片大小',
'imagepreview_imagesize_target' => '处理后图片大小',
@@ -6069,7 +6078,7 @@ $lang = array
'db_volume' => '卷数',
'db_export_tips_nouc' => '您当前的数据备份不包含 UCenter,会影响到您的会员数据,请点击这里 单独备份 UCenter 数据 数据备份功能根据您的选择备份全部Discuz!数据,导出的数据文件可用“数据恢复”功能或 phpMyAdmin 导入。 ',
'db_export_tips_uc' => '数据备份功能根据您的选择备份全部Discuz! 和 UCenter数据,导出的数据文件可用“数据恢复”功能或 phpMyAdmin 导入。 ',
- 'db_export_tips' => '全部备份均不包含模板文件和附件文件。模板、附件的备份只需通过 FTP 等下载 template/、data/attachment/ 目录即可,Discuz! 不提供单独备份。 MySQL Dump 的速度比 Discuz! 分卷备份快很多,但需要服务器支持相关的 Shell 权限,同时由于 MySQL 本身的兼容性问题,通常进行备份和恢复的服务器应当具有相同或相近的版本号才能顺利进行。因此 MySQL Dump 是有风险的:一旦进行备份或恢复操作的服务器其中之一禁止了 Shell,或由于版本兼容性问题导致导入失败,您将无法使用 MySQL Dump 备份或由备份数据恢复;Discuz! 分卷备份没有此限制。 数据备份选项中的设置,仅供高级用户的特殊用途使用,当您尚未对数据库做全面细致的了解之前,请使用默认参数备份,否则将导致备份数据错误等严重问题。 十六进制方式可以保证备份数据的完整性,但是备份文件会占用更多的空间。 压缩备份文件可以让您的备份文件占用更小的空间。 ',
+ 'db_export_tips' => '出于安全考虑,我们强烈建议您下载数据库备份文件后在恢复页面删除数据库数据库备份文件或设置数据库备份文件不可通过 URL 访问,以保证网站安全。 全部备份均不包含模板文件和附件文件。模板、附件的备份只需通过 FTP 等下载 template/、data/attachment/ 目录即可,Discuz! 不提供单独备份。 MySQL Dump 的速度比 Discuz! 分卷备份快很多,但需要服务器支持相关的 Shell 权限,同时由于 MySQL 本身的兼容性问题,通常进行备份和恢复的服务器应当具有相同或相近的版本号才能顺利进行。因此 MySQL Dump 是有风险的:一旦进行备份或恢复操作的服务器其中之一禁止了 Shell,或由于版本兼容性问题导致导入失败,您将无法使用 MySQL Dump 备份或由备份数据恢复;Discuz! 分卷备份没有此限制。 数据备份选项中的设置,仅供高级用户的特殊用途使用,当您尚未对数据库做全面细致的了解之前,请使用默认参数备份,否则将导致备份数据错误等严重问题。 十六进制方式可以保证备份数据的完整性,但是备份文件会占用更多的空间。 压缩备份文件可以让您的备份文件占用更小的空间。 ',
'db_export_type' => '数据备份类型',
'db_export_discuz' => 'Discuz! 数据(不含UCenter)',
'db_export_discuz_uc' => 'Discuz! 和 UCenter 数据',
@@ -6098,7 +6107,7 @@ $lang = array
'db_import_confirm' => '导入和当前 Discuz! 版本不一致的数据极有可能产生无法解决的故障,您确定继续吗?',
'db_import_confirm_sql' => '您确定导入该备份吗?',
'db_import_confirm_zip' => '您确定解压该备份吗?',
- 'db_import_tips' => '本功能在恢复备份数据的同时,将全部覆盖原有数据,请确定恢复前已将论坛关闭,恢复全部完成后可以将论坛重新开放。 恢复数据前请在 Discuz! 安装文件目录下 utility 文件夹内找到 restore.php 文件,然后将 restore.php 文件上传到程序文件夹data目录下。为了您站点的安全,成功恢复数据后请务必及时删除 restore.php 文件。 您可以在数据备份记录处查看站点的备份文件的详细信息,删除过期的备份,并导入需要的备份。 ',
+ 'db_import_tips' => '本功能在恢复备份数据的同时,将全部覆盖原有数据,请确定恢复前已将论坛关闭,恢复全部完成后可以将论坛重新开放。 出于安全考虑,我们强烈建议您下载数据库备份文件后在恢复页面删除数据库数据库备份文件或设置数据库备份文件不可通过 URL 访问,以保证网站安全。 恢复数据前请在 Discuz! 安装文件目录下 utility 文件夹内找到 restore.php 文件,然后将 restore.php 文件上传到程序文件夹data目录下。为了您站点的安全,成功恢复数据后请务必及时删除 restore.php 文件。 您可以在数据备份记录处查看站点的备份文件的详细信息,删除过期的备份,并导入需要的备份。 ',
'do_import_option' => ' 您可以在本页面数据备份记录处导入备份恢复数据,也可以通过在浏览器中执行 {restore_url} 恢复数据',
'db_import_from_server' => '从服务器(填写文件名或 URL)',
'db_import_from_local' => '从本地文件',
@@ -6943,6 +6952,7 @@ $lang = array
'optimizer_check_unit_optimizer_log' => '查看是否有需要优化清理的日志表',
'optimizer_check_unit_optimizer_seo' => '检测SEO优化设置',
'optimizer_check_unit_optimizer_dbbackup_clean' => '检测是否存在未删除的备份文件',
+ 'optimizer_check_unit_optimizer_dbbackup_visit' => '检测是否存在可访问的备份文件',
'optimizer_check_unit_optimizer_inviteregister' => '检测允许新用户注册项',
'optimizer_check_unit_optimizer_emailregister' => '检测通过邮件发送注册连接项',
'optimizer_check_unit_optimizer_pwlength' => '检测密码最小长度项',
@@ -6966,6 +6976,8 @@ $lang = array
'optimizer_check_unit_optimizer_security_daily' => '检测是否开启防水墙每日优化计划任务',
'optimizer_check_unit_optimizer_postqqonly' => '检测发帖需要绑定QQ号检测是否开启',
'optimizer_check_unit_optimizer_aggid' => '检测“管理员,超级版主,版主”QQ登录检测是否开启',
+ 'optimizer_check_unit_optimizer_filesafe' => '检测是否有升级或安装残留的文件',
+ 'optimizer_check_unit_optimizer_remote' => '检测是否有开启了远程调用',
'optimizer_check_unit_optimizer_dos8p3' => '检测 DOS 8.3 文件名支持是否开启',
'optimizer_check_unit_optimizer_httphost' => '检测空 HOST 访问是否开启',
@@ -7150,6 +7162,8 @@ url.rewrite-once = (
',
'detect_environment' => '运行环境检测',
+ 'version_tips' => '关于本版本的温馨提示',
+ 'version_tips_msg' => '感谢您选择 Discuz! {version} ,您可以查看 发行注记 以了解本版本更新内容。我们建议您尽快进行一次 安全检测 以及 底层安全检测 以尽可能保证系统安全。我已知晓 ',
'contributors' => 'Discuz! 开源贡献者',
'contributors_see' => 'Click Here To See Them',
'detect_environment_error' => '你的服务器无法检测新版,请点击查看新版',
diff --git a/upload/source/language/lang_admincp_login.php b/upload/source/language/lang_admincp_login.php
index 28e563075d6392f51b5556253c632356d699d05d..d740efc24457fa01daae7e0a11d9806b38f88b9d 100644
--- a/upload/source/language/lang_admincp_login.php
+++ b/upload/source/language/lang_admincp_login.php
@@ -33,6 +33,7 @@ $lang = array
'login_tips' => 'Discuz! 是 腾讯云 推出的以社区为基础的专业建站平台,帮助网站实现一站式服务。',
'login_nosecques' => '您还没有使用安全登录,请在个人中心设置您的安全提问后,再访问管理中心。您可以 点击这里 进入安全提问的设置。',
+ 'login_cp_guest' => '由于您尚未登录,本次请求已经被拒绝. 请 登录 后再试',
'login_cplock' => '您的管理面板已经锁定! 请在 {ltime} 秒以后重新访问管理中心',
'login_user_lock' => '由于您的登录密码错误次数过多,本次登录请求已经被拒绝. 请 15 分钟后重新尝试',
'login_cp_noaccess' => '管理中心(或此项操作)尚未对您开放 您的此次操作已经记录, 请勿非法尝试',
diff --git a/upload/source/language/lang_admincp_menu.php b/upload/source/language/lang_admincp_menu.php
index b5e24df3bd77e62e0bba06c30a34fb08057fb0ab..dec2934ec3441ac13d19c54838472f3769063a07 100644
--- a/upload/source/language/lang_admincp_menu.php
+++ b/upload/source/language/lang_admincp_menu.php
@@ -173,7 +173,7 @@ $lang = array
'menu_tools_fileperms' => '文件权限检查',
'menu_tools_hookcheck' => '嵌入点校验',
'menu_tools_filecheck' => '文件校验',
- 'menu_forum_scheme' => '站点方案管理',
+ 'menu_tools_replacekey' => '密钥更新',
'menu_db' => '数据库',
'menu_postsplit' => '帖子分表',
'menu_threadsplit' => '主题分表',
diff --git a/upload/source/language/lang_admincp_msg.php b/upload/source/language/lang_admincp_msg.php
index 80733547c56299a0d79cade053fe37bdf563a4e8..bf37a4db093cdaf52f9eae9dcc5cd53c073284dd 100644
--- a/upload/source/language/lang_admincp_msg.php
+++ b/upload/source/language/lang_admincp_msg.php
@@ -23,14 +23,16 @@ $lang = array (
'blogcategory_move_category_failed' => '无法移动日志到指定分类',
'blogcategory_delete_succeed' => '删除日志分类成功 ',
'filecheck_nofound_md5file' => '不存在校验文件,无法进行此操作 {upgradeurl}',
+ 'replacekey_must_write_config' => 'config_global.php 不可写,无法进行此操作',
+ 'replacekey_succeed' => '密钥更新成功,请重新登录站点并更新缓存',
'cloudaddons_download_error' => '数据下载错误({ErrorCode}),点击查看常见问题解决办法 ',
'cloudaddons_downloading' => '应用 {addonid} 下载中,请稍候 ......',
'collection_admin_updated' => '专辑管理操作成功',
'counter_member_succeed' => '用户发帖数重建完成',
'credits_update_succeed' => '积分规则更新成功 ',
'noaccess_isfounder' => '您没有权限访问该设置,出于安全考虑只有站点创始人可以使用,请检查 config/config_global.php 文件内创始人的设置',
- 'database_export_multivol_succeed' => '恭喜您,成功创建 {volume} 个备份文件,备份全部完成。 {filelist}',
- 'database_export_zip_succeed' => '数据成功备份并压缩至服务器 {filename} 中',
+ 'database_export_multivol_succeed' => '恭喜您,成功创建 {volume} 个备份文件,备份全部完成。出于安全考虑,我们强烈建议您下载数据库备份文件后在恢复页面删除数据库数据库备份文件或设置数据库备份文件不可通过 URL 访问,以保证网站安全。 {filelist}',
+ 'database_export_zip_succeed' => '数据成功备份并压缩至服务器 {filename} 中出于安全考虑,我们强烈建议您下载数据库备份文件后在恢复页面删除数据库数据库备份文件或设置数据库备份文件不可通过 URL 访问,以保证网站安全。 ',
'setting_update_succeed' => '当前设置更新成功 ',
'setting_domain_http_error' => '请您填写合法的域名,常见错误为以 “http://”、“.”开头或者以“/”、“/index.php”、“.”结尾,或域名包含未转换为 Punycode 的国际化域名等',
'orders_validate_succeed' => '订单处理成功 ',
@@ -223,7 +225,7 @@ $lang = array (
'database_export_custom_invalid' => '您至少需要选择一个数据表进行备份',
'database_export_file_invalid' => '数据文件无法保存到服务器,请检查目录属性',
'database_export_multivol_redirect' => '分卷备份:数据文件 #{volume} 创建成功,程序将自动继续',
- 'database_export_succeed' => '数据成功备份至服务器 {filename} 中',
+ 'database_export_succeed' => '数据成功备份至服务器 {filename} 中出于安全考虑,我们强烈建议您下载数据库备份文件后在恢复页面删除数据库数据库备份文件或设置数据库备份文件不可通过 URL 访问,以保证网站安全。 ',
'database_shell_fail' => 'Shell 权限被禁止或服务器不支持,无法使用 MySQL Dump 方式备份或恢复数据',
'database_export_dest_invalid' => '目录不存在或无法访问,请检查 ./data/ 目录',
'database_file_delete_succeed' => '指定备份文件删除成功 ',
@@ -658,6 +660,8 @@ $lang = array (
'attach_readmod_error' => '抱歉,当前的本地文件读取模式会导致部分浏览器下视频播放异常,如需开启附件URL地址、媒体附件播放,请在 config_global.php 内修改本地文件读取模式为 1 或 4 后再试',
'optimizer_dos8p3_optimizer' => '请您根据您底层的情况正确选择技术路线和解决方案, 通过对底层的正确配置以关闭 DOS 8.3 文件名支持',
'optimizer_httphost_optimizer' => '请您根据您底层的情况正确选择技术路线和解决方案, 通过对底层的正确配置以关闭空 HOST 头支持',
+ 'optimizer_filesafe_optimizer' => '已经尝试为您删除安装程序、数据恢复程序以及重复的后台入口文件, 如果检测仍异常则需要您自查相关目录文件是否存在, 尤其是 old 目录以及 utility 目录是否删除',
+ 'optimizer_remote_optimizer' => '如此功能并非您主动开启的, 请在 config_global.php 内关闭远程调用功能并修改远程密钥',
);
?>
\ No newline at end of file
diff --git a/upload/source/language/lang_optimizer.php b/upload/source/language/lang_optimizer.php
index 2940e0e736de353f9c4884d7612312e75155c306..b798d99e73c1b088deead5c3509afa4f74a4d3dd 100644
--- a/upload/source/language/lang_optimizer.php
+++ b/upload/source/language/lang_optimizer.php
@@ -17,6 +17,8 @@ $lang = array
'optimizer_dbbackup_lastback' => '上次数据备份于',
'optimizer_dbbackup_clean_safe' => '没有检测到数据库备份文件,无安全问题',
'optimizer_dbbackup_clean_delete' => '检测到 {filecount} 个数据备份文件(目录: ./data/backup_xxx), 请尽快手工复制到安全位置备份,然后删除这些文件',
+ 'optimizer_dbbackup_visit_safe' => '没有检测到可访问的数据库备份文件,无安全问题',
+ 'optimizer_dbbackup_visit_delete' => '检测到 {filecount} 个数据备份文件(目录: ./data/backup_xxx)可以通过 Web 方式访问, 请在数据库恢复页面删除数据库数据库备份文件或设置数据库备份文件不可通过 URL 访问',
'optimizer_filecheck_advice' => '三个月没有进行文件校验了,建议立即进行校验',
'optimizer_filecheck_lastcheck' => '上次文件校验于',
'optimizer_log_clean' => '有 {count} 个日志表可以清理优化',
@@ -71,6 +73,10 @@ $lang = array
'optimizer_emailregister_tip' => '此设置可以提升用户质量',
'optimizer_pwlength_need' => '密码最小长度过低,不安全',
'optimizer_pwlength_no_need' => '经检测密码长度设置正常',
+ 'optimizer_filesafe_need' => 'old 目录、utility 目录、安装程序、数据恢复程序或重复的管理员入口其中之一未删除',
+ 'optimizer_filesafe_no_need' => '文件安全检测正常',
+ 'optimizer_remote_need' => '您开启了正常站点无需开启的远程调用功能,请检查是否是主动开启',
+ 'optimizer_remote_no_need' => '远程调用功能关闭',
'optimizer_regmaildomain_need' => '需要优化黑名单列表',
'optimizer_regmaildomain_tip' => '可以设置邮箱域名限制阻止垃圾注册',
'optimizer_ipregctrl_no_need' => '已经设置了限时注册IP列表',
diff --git a/upload/uc_client/control/app.php b/upload/uc_client/control/app.php
index 5945f9bb22203d8685abbd87fc8f3618c1855c76..26b447e33614e9efe76584c1cb807b905dfe680a 100644
--- a/upload/uc_client/control/app.php
+++ b/upload/uc_client/control/app.php
@@ -37,12 +37,6 @@ class appcontrol extends base {
function onucinfo() {
}
- function _random($length, $numeric = 0) {
- }
-
- function _generate_key() {
- }
-
function _format_notedata($notedata) {
}
}
diff --git a/upload/uc_server/api/dbbak.php b/upload/uc_server/api/dbbak.php
index 50ec0a5cc513badf796d64d8f9d977285b36e02f..42b2aa53e9776e5a77c05b119fade37de09259a8 100644
--- a/upload/uc_server/api/dbbak.php
+++ b/upload/uc_server/api/dbbak.php
@@ -511,6 +511,10 @@ if($get['method'] == 'export') {
$get['volume'] = 0;
}
+ if(!preg_match('/^backup_(\d+)_\w+$/', $get['sqlpath']) || !preg_match('/^\d+_\w+\-(\d+).sql$/', $get['dumpfile'])) {
+ api_msg('bak_file_lose', $get['dumpfile']);
+ }
+
$get['volume']++;
$next_dumpfile = preg_replace('/^(\d+)\_(\w+)\-(\d+)\.sql$/', '\\1_\\2-'.$get['volume'].'.sql', $get['dumpfile']);
if(!is_file(BACKUP_DIR.$get['sqlpath'].'/'.$get['dumpfile'])) {
@@ -554,7 +558,7 @@ if($get['method'] == 'export') {
$directory = dir(BACKUP_DIR);
while($entry = $directory->read()) {
$filename = BACKUP_DIR.$entry;
- if(is_dir($filename) && preg_match('/backup_(\d+)_\w+$/', $filename, $match)) {
+ if(is_dir($filename) && preg_match('/^backup_(\d+)_\w+$/', $filename, $match)) {
$str .= "\t\n";
$str .= "\t\t$filename \n";
$str .= "\t\t$match[1] \n";
diff --git a/upload/uc_server/control/admin/admin.php b/upload/uc_server/control/admin/admin.php
index ad31f89f02ddf1770cfc410b18ee14d1c6a1fe0c..54955c8603328ce9170a7403dc6d409ee63cb0eb 100644
--- a/upload/uc_server/control/admin/admin.php
+++ b/upload/uc_server/control/admin/admin.php
@@ -80,6 +80,7 @@ class control extends adminbase {
$oldpw = getgpc('oldpw', 'P');
$newpw = getgpc('newpw', 'P');
$newpw2 = getgpc('newpw2', 'P');
+ $reconfkey = getgpc('reconfkey', 'P');
if(UC_FOUNDERPW == md5(md5($oldpw).UC_FOUNDERSALT)) {
$configfile = UC_ROOT.'./data/config.inc.php';
if(!is_writable($configfile)) {
@@ -93,6 +94,10 @@ class control extends adminbase {
$md5newpw = md5(md5($newpw).$salt);
$config = preg_replace("/define\('UC_FOUNDERSALT',\s*'.*?'\);/i", "define('UC_FOUNDERSALT', '$salt');", $config);
$config = preg_replace("/define\('UC_FOUNDERPW',\s*'.*?'\);/i", "define('UC_FOUNDERPW', '$md5newpw');", $config);
+ if($reconfkey) {
+ $uckey = $this->generate_key(64);
+ $config = preg_replace("/define\('UC_KEY',\s*'.*?'\);/i", "define('UC_KEY', '$uckey');", $config);
+ }
$fp = @fopen($configfile, 'w');
@fwrite($fp, $config);
@fclose($fp);
diff --git a/upload/uc_server/control/admin/app.php b/upload/uc_server/control/admin/app.php
index 47f31f34fb31b361e6e85fb0e5caf5b6c92acd94..c5d5e26c7a530b929f055cf8da43a251224e2af9 100644
--- a/upload/uc_server/control/admin/app.php
+++ b/upload/uc_server/control/admin/app.php
@@ -136,6 +136,12 @@ class control extends adminbase {
}
+ function ongeneratekey() {
+ $newkey = $this->generate_key(64);
+ header("Content-Type: application/javascript");
+ echo 'document.getElementsByName("authkey")[0].value = "'.$newkey.'";';
+ }
+
function ondetail() {
$appid = getgpc('appid');
$updated = false;
diff --git a/upload/uc_server/control/app.php b/upload/uc_server/control/app.php
index 874d4ba75e3e5aac084e286f3f16d5ca4d30ebb4..425279a7610bac49921608fa18bd7a54ef93b76f 100644
--- a/upload/uc_server/control/app.php
+++ b/upload/uc_server/control/app.php
@@ -60,7 +60,7 @@ class appcontrol extends base {
$app = $this->db->fetch_first("SELECT * FROM ".UC_DBTABLEPRE."applications WHERE url='$appurl' AND type='$apptype'");
if(empty($app)) {
- $authkey = $this->_generate_key();
+ $authkey = $this->generate_key(64);
$apptagtemplates = $this->serialize($apptagtemplates, 1);
$this->db->query("INSERT INTO ".UC_DBTABLEPRE."applications SET
name='$appname',
@@ -118,31 +118,6 @@ class appcontrol extends base {
exit("UC_STATUS_OK|".UC_SERVER_VERSION."|".UC_SERVER_RELEASE."|".UC_CHARSET."|".UC_DBCHARSET."|".$apptypes);
}
- function _random($length, $numeric = 0) {
- PHP_VERSION < '4.2.0' && mt_srand((double)microtime() * 1000000);
- if($numeric) {
- $hash = sprintf('%0'.$length.'d', mt_rand(0, pow(10, $length) - 1));
- } else {
- $hash = '';
- $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz';
- $max = strlen($chars) - 1;
- for($i = 0; $i < $length; $i++) {
- $hash .= $chars[mt_rand(0, $max)];
- }
- }
- return $hash;
- }
-
- function _generate_key() {
- $random = $this->_random(32);
- $info = md5($_SERVER['SERVER_SOFTWARE'].$_SERVER['SERVER_NAME'].$_SERVER['SERVER_ADDR'].$_SERVER['SERVER_PORT'].$_SERVER['HTTP_USER_AGENT'].time());
- $return = array();
- for($i=0; $i<32; $i++) {
- $return[$i] = $random[$i].$info[$i];
- }
- return implode('', $return);
- }
-
function _format_notedata($notedata) {
$arr = array();
foreach($notedata as $key => $note) {
diff --git a/upload/uc_server/install/func.inc.php b/upload/uc_server/install/func.inc.php
index 2715d647aeb55190ec3656fa61176015f7c75d15..816a744763de9b06fac8ab16f9cce0ae352c35b7 100644
--- a/upload/uc_server/install/func.inc.php
+++ b/upload/uc_server/install/func.inc.php
@@ -632,15 +632,14 @@ function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
}
-function generate_key() {
- $random = random(32);
+function generate_key($length = 32) {
+ $random = random($length);
$info = md5($_SERVER['SERVER_SOFTWARE'].$_SERVER['SERVER_NAME'].$_SERVER['SERVER_ADDR'].$_SERVER['SERVER_PORT'].$_SERVER['HTTP_USER_AGENT'].time());
- $return = array();
- for($i=0; $i<64; $i++) {
- $p = intval($i/2);
- $return[$i] = $i % 2 ? $random[$p] : $info[$p];
+ $return = '';
+ for($i=0; $i<$length; $i++) {
+ $return .= $random[$i].$info[$i];
}
- return implode('', $return);
+ return $return;
}
function show_install() {
diff --git a/upload/uc_server/model/base.php b/upload/uc_server/model/base.php
index 75e887f9fe9deceade29656a295f720adbf9efec..831f574b02acb9b9c748df64c3cdb488a40b08fd 100644
--- a/upload/uc_server/model/base.php
+++ b/upload/uc_server/model/base.php
@@ -521,6 +521,31 @@ class base {
return TRUE;
}
+ function random($length, $numeric = 0) {
+ PHP_VERSION < '4.2.0' && mt_srand((double)microtime() * 1000000);
+ if($numeric) {
+ $hash = sprintf('%0'.$length.'d', mt_rand(0, pow(10, $length) - 1));
+ } else {
+ $hash = '';
+ $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz';
+ $max = strlen($chars) - 1;
+ for($i = 0; $i < $length; $i++) {
+ $hash .= $chars[mt_rand(0, $max)];
+ }
+ }
+ return $hash;
+ }
+
+ function generate_key($length = 32) {
+ $random = $this->random($length);
+ $info = md5($_SERVER['SERVER_SOFTWARE'].$_SERVER['SERVER_NAME'].$_SERVER['SERVER_ADDR'].$_SERVER['SERVER_PORT'].$_SERVER['HTTP_USER_AGENT'].time());
+ $return = '';
+ for($i=0; $i<$length; $i++) {
+ $return .= $random[$i].$info[$i];
+ }
+ return $return;
+ }
+
}
?>
\ No newline at end of file
diff --git a/upload/uc_server/plugin/replacemykey/index.htm b/upload/uc_server/plugin/replacemykey/index.htm
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/upload/uc_server/plugin/replacemykey/plugin.php b/upload/uc_server/plugin/replacemykey/plugin.php
new file mode 100644
index 0000000000000000000000000000000000000000..1697d38bc302183b3b73ae8a3cdb87044bd03bd5
--- /dev/null
+++ b/upload/uc_server/plugin/replacemykey/plugin.php
@@ -0,0 +1,54 @@
+pluginbase();
+ }
+
+ function onindex() {
+
+ if($this->submitcheck()) {
+ if(!getgpc('reconfkey', 'P')) {
+ $this->message('replacemykey_no_confirm', 'BACK');
+ }
+ if($this->_replacemykey()) {
+ $this->message('replacemykey_succeed', 'BACK');
+ } else {
+ $this->message('replacemykey_false', 'BACK');
+ }
+ }
+
+ $this->view->display('plugin_replacemykey');
+ }
+
+ function _replacemykey() {
+ $oldmykey = UC_MYKEY;
+ $newmykey = $this->generate_key();
+ $configfile = UC_ROOT.'./data/config.inc.php';
+ if(!is_writable($configfile)) {
+ return false;
+ }
+ $config = file_get_contents($configfile);
+ $config = preg_replace("/define\('UC_MYKEY',\s*'.*?'\);/i", "define('UC_MYKEY', '$newmykey');", $config);
+ if(file_put_contents($configfile, $config, LOCK_EX) === false) {
+ return false;
+ }
+ $apps = $this->db->fetch_all("SELECT appid, authkey FROM ".UC_DBTABLEPRE."applications", 'appid');
+ foreach($apps as $k => $v) {
+ if($tmp = $this->authcode($v['authkey'], 'DECODE', $oldmykey)) {
+ $appid = $v['appid'];
+ $appkey = $this->authcode($tmp, 'ENCODE', $newmykey);
+ $this->db->query("UPDATE ".UC_DBTABLEPRE."applications SET authkey='$appkey' WHERE appid='$appid'");
+ if($this->db->errno()) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+}
\ No newline at end of file
diff --git a/upload/uc_server/plugin/replacemykey/plugin.xml b/upload/uc_server/plugin/replacemykey/plugin.xml
new file mode 100644
index 0000000000000000000000000000000000000000..baf4d052202f37fd82826150a8fb38871fc1c9a3
--- /dev/null
+++ b/upload/uc_server/plugin/replacemykey/plugin.xml
@@ -0,0 +1,16 @@
+
+
+ - 密钥更新
+ - 1.0.0
+ - Discuz! X Community Team
+ - 2022-1-30
+ - 2022-1-30
+ - Discuz! X Community Team
+ - 2
+ - 当站点沦陷时您应该考虑进行密钥更新,以避免黑客通过已知的 UC_MYKEY 密钥破解 UC_KEY 密钥。
+ -
+
- 在操作之前建议您选择低峰期操作或临时关闭下挂网站,并做好 UCenter 以及各应用的数据、文件备份工作。
+ - 确认
+ - 我已了解上述风险,并已经做好网站备份工作。
+
+
\ No newline at end of file
diff --git a/upload/uc_server/plugin/replacemykey/plugin_replacemykey.htm b/upload/uc_server/plugin/replacemykey/plugin_replacemykey.htm
new file mode 100644
index 0000000000000000000000000000000000000000..4e0f8dd2a20b356ecbe56ea9a7474f9cb318d2ea
--- /dev/null
+++ b/upload/uc_server/plugin/replacemykey/plugin_replacemykey.htm
@@ -0,0 +1,18 @@
+{template plugin_header}
+{lang plugin_replacemykey_tips}
+
+{template plugin_footer}
\ No newline at end of file
diff --git a/upload/uc_server/view/default/admin_admin.htm b/upload/uc_server/view/default/admin_admin.htm
index 0782ffb4efb929ab37f74c9ce2a1ed39217ea897..bc01e81975e7f9712d5a8f33af04610f014fd921 100644
--- a/upload/uc_server/view/default/admin_admin.htm
+++ b/upload/uc_server/view/default/admin_admin.htm
@@ -119,6 +119,10 @@
{lang repeatpw}:
+
+ {lang reconfkey}:
+ {lang reconfkey}
+
diff --git a/upload/uc_server/view/default/admin_app.htm b/upload/uc_server/view/default/admin_app.htm
index 99b51255966bc4b8ff168d470d49d63db871f8d1..f96b4bea70ad800cca48729f5628cdb56d6e56ec 100644
--- a/upload/uc_server/view/default/admin_app.htm
+++ b/upload/uc_server/view/default/admin_app.htm
@@ -11,6 +11,12 @@ function testlink() {
}
run++;
}
+function generatekey() {
+ var scriptNode = document.createElement('script');
+ scriptNode.type = 'text/javascript';
+ scriptNode.src = 'admin.php?m=app&a=generatekey&inajax=1&sid=$sid';
+ document.getElementsByTagName('head')[0].appendChild(scriptNode);
+}
window.onload = testlink;
@@ -135,7 +141,7 @@ window.onload = testlink;
- {lang app_key_comment}
+ {lang app_key_comment} {lang app_key_generate}
@@ -267,7 +273,7 @@ window.onload = testlink;
- {lang app_key_comment}
+ {lang app_key_comment} {lang app_key_generate}
diff --git a/upload/uc_server/view/default/admin_db.htm b/upload/uc_server/view/default/admin_db.htm
index 9b0b5d7ff158fc4dcf61cf7f7e18a0c4cef83c89..86ea7e9a6033e11957533755f23055f1a8b08957 100644
--- a/upload/uc_server/view/default/admin_db.htm
+++ b/upload/uc_server/view/default/admin_db.htm
@@ -11,6 +11,9 @@
+
+
{lang db_security_tips}
+