mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2026-09-22 08:00:53 +00:00
feat: support firewall port whitelist management (#12912)
This commit is contained in:
@@ -25,6 +25,8 @@ type SettingInfo struct {
|
||||
|
||||
FileRecycleBin string `json:"fileRecycleBin"`
|
||||
LocalSSHConnShow string `json:"localSSHConnShow"`
|
||||
|
||||
FirewallPortWhiteList string `json:"firewallPortWhiteList"`
|
||||
}
|
||||
|
||||
type SettingUpdate struct {
|
||||
@@ -33,7 +35,7 @@ type SettingUpdate struct {
|
||||
}
|
||||
|
||||
type AgentSettingUpdate struct {
|
||||
Key string `json:"key" validate:"required,oneof=SystemIP DockerSockPath FileRecycleBin"`
|
||||
Key string `json:"key" validate:"required,oneof=SystemIP DockerSockPath FileRecycleBin FirewallPortWhiteList"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
|
||||
@@ -579,30 +579,14 @@ func (u *FirewallService) cleanUnUsedData(client firewall.FirewallClient) {
|
||||
}
|
||||
|
||||
func (u *FirewallService) addPortsBeforeStart(client firewall.FirewallClient) error {
|
||||
if !global.IsMaster {
|
||||
if err := client.Port(fireClient.FireInfo{Port: global.CONF.Base.Port, Protocol: "tcp", Strategy: "accept"}, "add"); err != nil {
|
||||
portWhiteList, err := loadFirewallPortWhiteList()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, item := range portWhiteList {
|
||||
if err := client.Port(fireClient.FireInfo{Port: item.Port, Protocol: item.Protocol, Strategy: "accept"}, "add"); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
var portSetting model.Setting
|
||||
_ = global.CoreDB.Where("key = ?", "ServerPort").First(&portSetting).Error
|
||||
if len(portSetting.Value) != 0 {
|
||||
if err := client.Port(fireClient.FireInfo{Port: portSetting.Value, Protocol: "tcp", Strategy: "accept"}, "add"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := client.Port(fireClient.FireInfo{Port: loadSSHPort(), Protocol: "tcp", Strategy: "accept"}, "add"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := client.Port(fireClient.FireInfo{Port: "80", Protocol: "tcp", Strategy: "accept"}, "add"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := client.Port(fireClient.FireInfo{Port: "443", Protocol: "tcp", Strategy: "accept"}, "add"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := client.Port(fireClient.FireInfo{Port: "443", Protocol: "udp", Strategy: "accept"}, "add"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return client.Reload()
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/constant"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/firewall"
|
||||
fireClient "github.com/1Panel-dev/1Panel/agent/utils/firewall/client"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/firewall/client/iptables"
|
||||
)
|
||||
|
||||
type firewallPortWhitelist struct {
|
||||
Port string
|
||||
Protocol string
|
||||
}
|
||||
|
||||
func loadFirewallPortWhiteList() ([]firewallPortWhitelist, error) {
|
||||
value, err := settingRepo.GetValueByKey(constant.FirewallPortWhiteList)
|
||||
if err != nil {
|
||||
value = constant.FirewallPortWhiteListValue
|
||||
if err := settingRepo.UpdateOrCreate(constant.FirewallPortWhiteList, value); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return parseFullFirewallPortWhiteList(value)
|
||||
}
|
||||
|
||||
func parseFullFirewallPortWhiteList(value string) ([]firewallPortWhitelist, error) {
|
||||
portWhiteList, err := parseFirewallPortWhiteList(value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
panelPort := LoadPanelPort()
|
||||
if panelPort == "" {
|
||||
return nil, fmt.Errorf("find 1panel service port failed")
|
||||
}
|
||||
portWhiteList = append(portWhiteList, firewallPortWhitelist{Port: panelPort, Protocol: "tcp"})
|
||||
portWhiteList = append(portWhiteList, firewallPortWhitelist{Port: loadSSHPort(), Protocol: "tcp"})
|
||||
return normalizeFirewallPortWhiteList(portWhiteList), nil
|
||||
}
|
||||
|
||||
func parseFirewallPortWhiteList(value string) ([]firewallPortWhitelist, error) {
|
||||
items := strings.FieldsFunc(value, func(r rune) bool {
|
||||
return r == ',' || r == '\n' || r == ';' || r == ' '
|
||||
})
|
||||
ports := make([]firewallPortWhitelist, 0, len(items))
|
||||
exists := make(map[string]struct{})
|
||||
for _, item := range items {
|
||||
item = strings.TrimSpace(item)
|
||||
if item == "" {
|
||||
continue
|
||||
}
|
||||
port, protocol, ok := strings.Cut(item, "/")
|
||||
if !ok {
|
||||
protocol = "tcp"
|
||||
}
|
||||
port = strings.TrimSpace(port)
|
||||
protocol = strings.ToLower(strings.TrimSpace(protocol))
|
||||
if protocol != "tcp" && protocol != "udp" {
|
||||
return nil, fmt.Errorf("invalid firewall port whitelist protocol: %s", item)
|
||||
}
|
||||
portNum, err := strconv.Atoi(port)
|
||||
if err != nil || portNum < 1 || portNum > 65535 {
|
||||
return nil, fmt.Errorf("invalid firewall port whitelist: %s", item)
|
||||
}
|
||||
key := fmt.Sprintf("%d/%s", portNum, protocol)
|
||||
if _, ok := exists[key]; ok {
|
||||
continue
|
||||
}
|
||||
exists[key] = struct{}{}
|
||||
ports = append(ports, firewallPortWhitelist{Port: strconv.Itoa(portNum), Protocol: protocol})
|
||||
}
|
||||
return ports, nil
|
||||
}
|
||||
|
||||
func normalizeFirewallPortWhiteList(portWhiteList []firewallPortWhitelist) []firewallPortWhitelist {
|
||||
ports := make([]firewallPortWhitelist, 0, len(portWhiteList))
|
||||
exists := make(map[string]struct{})
|
||||
for _, item := range portWhiteList {
|
||||
if item.Port == "" {
|
||||
continue
|
||||
}
|
||||
key := fmt.Sprintf("%s/%s", item.Port, item.Protocol)
|
||||
if _, ok := exists[key]; ok {
|
||||
continue
|
||||
}
|
||||
exists[key] = struct{}{}
|
||||
ports = append(ports, item)
|
||||
}
|
||||
return ports
|
||||
}
|
||||
|
||||
func syncFirewallPortWhiteListAfterUpdate(oldValue string) error {
|
||||
client, err := firewall.NewFirewallClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
portWhiteList, err := loadFirewallPortWhiteList()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if client.Name() != "iptables" {
|
||||
oldPortWhiteList, err := parseFullFirewallPortWhiteList(oldValue)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return syncFirewallClientPortWhiteList(client, oldPortWhiteList, portWhiteList)
|
||||
}
|
||||
isInit, _ := iptables.LoadInitStatus("iptables", "base")
|
||||
if !isInit {
|
||||
return nil
|
||||
}
|
||||
return applyFirewallPortWhiteListRules(portWhiteList, true)
|
||||
}
|
||||
|
||||
func syncFirewallClientPortWhiteList(client firewall.FirewallClient, oldPortWhiteList, portWhiteList []firewallPortWhitelist) error {
|
||||
oldPorts := firewallPortWhiteListMap(oldPortWhiteList)
|
||||
newPorts := firewallPortWhiteListMap(portWhiteList)
|
||||
for _, item := range oldPortWhiteList {
|
||||
key := firewallPortWhiteListKey(item)
|
||||
if _, ok := newPorts[key]; ok {
|
||||
continue
|
||||
}
|
||||
if err := client.Port(fireClient.FireInfo{Port: item.Port, Protocol: item.Protocol, Strategy: "accept"}, "remove"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, item := range portWhiteList {
|
||||
key := firewallPortWhiteListKey(item)
|
||||
if _, ok := oldPorts[key]; ok {
|
||||
continue
|
||||
}
|
||||
if err := client.Port(fireClient.FireInfo{Port: item.Port, Protocol: item.Protocol, Strategy: "accept"}, "add"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return client.Reload()
|
||||
}
|
||||
|
||||
func firewallPortWhiteListMap(portWhiteList []firewallPortWhitelist) map[string]struct{} {
|
||||
ports := make(map[string]struct{})
|
||||
for _, item := range portWhiteList {
|
||||
ports[firewallPortWhiteListKey(item)] = struct{}{}
|
||||
}
|
||||
return ports
|
||||
}
|
||||
|
||||
func firewallPortWhiteListKey(item firewallPortWhitelist) string {
|
||||
return item.Port + "/" + item.Protocol
|
||||
}
|
||||
@@ -228,6 +228,12 @@ func (s *IptablesService) Operate(req dto.IptablesOp) error {
|
||||
if err := iptables.BindChain(iptables.FilterTab, iptables.ChainInput, iptables.Chain1PanelBasicAfter, 3); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := iptables.SaveRulesToFile(iptables.FilterTab, iptables.Chain1PanelBasicBefore, iptables.BasicBeforeFileName); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := iptables.SaveRulesToFile(iptables.FilterTab, iptables.Chain1PanelBasicAfter, iptables.BasicAfterFileName); err != nil {
|
||||
return err
|
||||
}
|
||||
_ = settingRepo.Update("IptablesStatus", constant.StatusEnable)
|
||||
return nil
|
||||
case "bind-base-without-init":
|
||||
@@ -365,17 +371,11 @@ func initPreRules() error {
|
||||
if err := iptables.AddRule(iptables.FilterTab, iptables.Chain1PanelBasicBefore, "-m", "conntrack", "--ctstate", "RELATED,ESTABLISHED", "-j", "ACCEPT", "-m", "comment", "--comment", "ESTABLISHED Whitelist"); err != nil {
|
||||
return err
|
||||
}
|
||||
panelPort := LoadPanelPort()
|
||||
if len(panelPort) == 0 {
|
||||
return errors.New("find 1panel service port failed")
|
||||
portWhiteList, err := loadFirewallPortWhiteList()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ports := []string{"80", "443", panelPort, loadSSHPort()}
|
||||
for _, item := range ports {
|
||||
if err := iptables.AddRule(iptables.FilterTab, iptables.Chain1PanelBasicBefore, "-p", "tcp", "-m", "tcp", "--dport", item, "-j", "ACCEPT"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := iptables.AddRule(iptables.FilterTab, iptables.Chain1PanelBasicAfter, "-p", "udp", "-m", "udp", "--dport", "443", "-j", "ACCEPT"); err != nil {
|
||||
if err := applyFirewallPortWhiteListRules(portWhiteList, false); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := iptables.AddRule(iptables.FilterTab, iptables.Chain1PanelBasicAfter, "-p", "tcp", "-j", "DROP"); err != nil {
|
||||
@@ -387,6 +387,67 @@ func initPreRules() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func applyFirewallPortWhiteListRules(portWhiteList []firewallPortWhitelist, withSave bool) error {
|
||||
if err := syncFirewallPortWhiteListRules(portWhiteList); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, item := range portWhiteList {
|
||||
if err := iptables.AddRule(iptables.FilterTab, iptables.Chain1PanelBasicBefore, "-p", item.Protocol, "-m", item.Protocol, "--dport", item.Port, "-j", "ACCEPT"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if !withSave {
|
||||
return nil
|
||||
}
|
||||
if err := iptables.SaveRulesToFile(iptables.FilterTab, iptables.Chain1PanelBasicBefore, iptables.BasicBeforeFileName); err != nil {
|
||||
return err
|
||||
}
|
||||
return iptables.SaveRulesToFile(iptables.FilterTab, iptables.Chain1PanelBasicAfter, iptables.BasicAfterFileName)
|
||||
}
|
||||
|
||||
func syncFirewallPortWhiteListRules(portWhiteList []firewallPortWhitelist) error {
|
||||
tcpWhitelist := make(map[string]struct{})
|
||||
udpWhitelist := make(map[string]struct{})
|
||||
for _, item := range portWhiteList {
|
||||
if item.Protocol == "udp" {
|
||||
udpWhitelist[item.Port] = struct{}{}
|
||||
continue
|
||||
}
|
||||
tcpWhitelist[item.Port] = struct{}{}
|
||||
}
|
||||
|
||||
if err := cleanExtraFirewallPortRules(iptables.Chain1PanelBasicBefore, "tcp", tcpWhitelist); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cleanExtraFirewallPortRules(iptables.Chain1PanelBasicBefore, "udp", udpWhitelist); err != nil {
|
||||
return err
|
||||
}
|
||||
return cleanExtraFirewallPortRules(iptables.Chain1PanelBasicAfter, "udp", map[string]struct{}{})
|
||||
}
|
||||
|
||||
func cleanExtraFirewallPortRules(chain, protocol string, whitelist map[string]struct{}) error {
|
||||
rules, err := iptables.ReadFilterRulesByChain(chain)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
kept := make(map[string]struct{})
|
||||
for _, rule := range rules {
|
||||
if rule.Strategy != "accept" || rule.Protocol != protocol || rule.DstPort == "" || rule.SrcIP != "" || rule.DstIP != "" || rule.SrcPort != "" {
|
||||
continue
|
||||
}
|
||||
if _, ok := whitelist[rule.DstPort]; ok {
|
||||
if _, seen := kept[rule.DstPort]; !seen {
|
||||
kept[rule.DstPort] = struct{}{}
|
||||
continue
|
||||
}
|
||||
}
|
||||
if err := iptables.DeleteRule(iptables.FilterTab, chain, "-p", protocol, "-m", protocol, "--dport", rule.DstPort, "-j", "ACCEPT"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func LoadPanelPort() string {
|
||||
if !global.IsMaster {
|
||||
return global.CONF.Base.Port
|
||||
|
||||
@@ -124,7 +124,22 @@ func (u *SettingService) GetWebsiteDir() string {
|
||||
}
|
||||
|
||||
func (u *SettingService) Update(key, value string) error {
|
||||
return settingRepo.UpdateOrCreate(key, value)
|
||||
oldValue := constant.FirewallPortWhiteListValue
|
||||
if key == constant.FirewallPortWhiteList {
|
||||
if _, err := parseFirewallPortWhiteList(value); err != nil {
|
||||
return err
|
||||
}
|
||||
if val, err := settingRepo.GetValueByKey(key); err == nil {
|
||||
oldValue = val
|
||||
}
|
||||
}
|
||||
if err := settingRepo.UpdateOrCreate(key, value); err != nil {
|
||||
return err
|
||||
}
|
||||
if key == constant.FirewallPortWhiteList {
|
||||
return syncFirewallPortWhiteListAfterUpdate(oldValue)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *SettingService) UpdateTerminalAI(req dto.TerminalAIInfo) error {
|
||||
|
||||
@@ -7,6 +7,9 @@ const (
|
||||
|
||||
SystemRestart = "systemRestart"
|
||||
|
||||
FirewallPortWhiteList = "FirewallPortWhiteList"
|
||||
FirewallPortWhiteListValue = "80/tcp,443/tcp,443/udp"
|
||||
|
||||
TypeWebsite = "website"
|
||||
TypePhp = "php"
|
||||
TypeSSL = "ssl"
|
||||
|
||||
@@ -84,6 +84,7 @@ func InitAgentDB() {
|
||||
migrations.AddFileShareTable,
|
||||
migrations.AddFileHistoryTable,
|
||||
migrations.MigrateLegoV5,
|
||||
migrations.InitFirewallPortWhiteList,
|
||||
})
|
||||
if err := m.Migrate(); err != nil {
|
||||
global.LOG.Error(err)
|
||||
|
||||
@@ -846,6 +846,23 @@ var InitIptablesStatus = &gormigrate.Migration{
|
||||
if err := tx.Create(&model.Setting{Key: "IptablesOutputStatus", Value: constant.StatusDisable}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Create(&model.Setting{Key: constant.FirewallPortWhiteList, Value: constant.FirewallPortWhiteListValue}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var InitFirewallPortWhiteList = &gormigrate.Migration{
|
||||
ID: "20260601-init-firewall-port-whitelist",
|
||||
Migrate: func(tx *gorm.DB) error {
|
||||
var setting model.Setting
|
||||
if err := tx.Where("key = ?", constant.FirewallPortWhiteList).First(&setting).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return tx.Create(&model.Setting{Key: constant.FirewallPortWhiteList, Value: constant.FirewallPortWhiteListValue}).Error
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ export namespace Setting {
|
||||
|
||||
fileRecycleBin: string;
|
||||
localSSHConnShow: string;
|
||||
firewallPortWhiteList: string;
|
||||
}
|
||||
export interface SettingInfo {
|
||||
systemVersion: string;
|
||||
|
||||
@@ -3769,6 +3769,11 @@ const message = {
|
||||
bindHelper: 'Bind - Firewall rules will only take effect when the status is bound. Confirm?',
|
||||
unbindHelper:
|
||||
'Unbind - When unbound, all added firewall rules will become invalid. Proceed with caution. Confirm?',
|
||||
whiteList: 'Allowlist',
|
||||
portWhiteList: 'Port allowlist',
|
||||
portWhiteListAlter:
|
||||
'Ports in the allowlist are opened automatically when the firewall is initialized or started.',
|
||||
portWhiteListHelper: 'Protocol can be specified, e.g. 80/tcp or 443/udp. Defaults to tcp when omitted.',
|
||||
defaultStrategy: 'Default policy for current chain {0} is {1}',
|
||||
defaultStrategy2:
|
||||
'Default policy for current chain {0} is {1}, current status is unbound. Added firewall rules will take effect after binding!',
|
||||
|
||||
@@ -3819,6 +3819,12 @@ const message = {
|
||||
'Vincular: las reglas de firewall solo surtirán efecto cuando el estado esté vinculado. ¿Confirmar?',
|
||||
unbindHelper:
|
||||
'Desvincular: al desvincular, todas las reglas de firewall agregadas se volverán inválidas. Proceda con precaución. ¿Confirmar?',
|
||||
whiteList: 'Lista blanca',
|
||||
portWhiteList: 'Lista blanca de puertos',
|
||||
portWhiteListAlter:
|
||||
'Los puertos de la lista blanca se abrirán automáticamente al inicializar o iniciar el firewall.',
|
||||
portWhiteListHelper:
|
||||
'Puede especificar el protocolo, por ejemplo 80/tcp o 443/udp. Si se omite, se usa tcp por defecto.',
|
||||
defaultStrategy: 'La política predeterminada para la cadena actual {0} es {1}',
|
||||
defaultStrategy2:
|
||||
'La política predeterminada para la cadena actual {0} es {1}, el estado actual es no vinculado. ¡Las reglas de firewall agregadas surtirán efecto después de la vinculación!',
|
||||
@@ -4096,7 +4102,8 @@ const message = {
|
||||
scoreWebsiteHTTP: '{0} no usa HTTPS',
|
||||
scoreWebsiteStopped: 'Estado anormal de {0}',
|
||||
scoreWebsiteMonitorUnavailable: 'El monitoreo web detectó un sitio no disponible',
|
||||
scoreWebsiteMonitorAvailability: 'La disponibilidad del monitoreo web ({0}%) está por debajo del umbral',
|
||||
scoreWebsiteMonitorAvailability:
|
||||
'La disponibilidad del monitoreo web ({0}%) está por debajo del umbral',
|
||||
scoreWafDisabled: 'WAF deshabilitado, los sitios web no están protegidos',
|
||||
scoreWafHighRiskHit: 'WAF detectó {0} reglas de riesgo en el periodo del informe',
|
||||
scoreCronjobFailed: '{0} registros de fallos de tareas programadas en los últimos 7 días',
|
||||
@@ -4202,8 +4209,10 @@ const message = {
|
||||
'Se detectaron {0} configuraciones de riesgo. Refuerce la seguridad de acceso para reducir el riesgo de intrusión.',
|
||||
loginHealthNormalDesc: 'Las configuraciones de acceso y SSH están en estado normal',
|
||||
loginHealthNormalReason: 'La seguridad de acceso es normal',
|
||||
securityEntranceConfiguredDesc: 'Entrada de seguridad configurada para reducir la exposición de la entrada predeterminada',
|
||||
securityEntranceRiskDesc: 'Entrada de seguridad deshabilitada. Se recomienda ocultar la entrada predeterminada',
|
||||
securityEntranceConfiguredDesc:
|
||||
'Entrada de seguridad configurada para reducir la exposición de la entrada predeterminada',
|
||||
securityEntranceRiskDesc:
|
||||
'Entrada de seguridad deshabilitada. Se recomienda ocultar la entrada predeterminada',
|
||||
allowIPsRestrictedDesc: 'IPs autorizadas restringidas para el acceso al panel',
|
||||
allowIPsRiskDesc: 'IPs de acceso sin restricciones. Configure IPs autorizadas para entornos públicos',
|
||||
bindDomainRestrictedDesc: 'Dominio de acceso vinculado',
|
||||
@@ -4223,11 +4232,15 @@ const message = {
|
||||
mfaRiskDesc: 'Autenticación MFA deshabilitada. Se recomienda habilitar la autenticación multifactor',
|
||||
passwordExpiration: 'Fecha de vencimiento de contraseña',
|
||||
passwordExpirationNormalDesc: 'La fecha de vencimiento de contraseña está en un rango seguro',
|
||||
passwordExpirationUnsetDesc: 'Fecha de vencimiento de contraseña no configurada. Se recomienda configurarla pronto',
|
||||
passwordExpirationRiskDesc: 'La contraseña vence en {0} días. Se recomienda gestionarla con anticipación',
|
||||
passwordExpirationExpiredDesc: 'La contraseña expiró hace {0} días. Por favor, gestionar lo antes posible',
|
||||
passwordExpirationUnsetDesc:
|
||||
'Fecha de vencimiento de contraseña no configurada. Se recomienda configurarla pronto',
|
||||
passwordExpirationRiskDesc:
|
||||
'La contraseña vence en {0} días. Se recomienda gestionarla con anticipación',
|
||||
passwordExpirationExpiredDesc:
|
||||
'La contraseña expiró hace {0} días. Por favor, gestionar lo antes posible',
|
||||
sessionTimeoutNormalDesc: 'El tiempo de espera de sesión está en un rango seguro',
|
||||
sessionTimeoutRiskDesc: 'Tiempo de espera de sesión largo. Se recomienda limitar la duración de sesiones inactivas',
|
||||
sessionTimeoutRiskDesc:
|
||||
'Tiempo de espera de sesión largo. Se recomienda limitar la duración de sesiones inactivas',
|
||||
sshServiceNormalDesc: 'El servicio SSH está ejecutándose normalmente',
|
||||
sshServiceRiskDesc: 'El servicio SSH no está ejecutándose o está en estado anormal',
|
||||
sshPortNormalDesc: 'El puerto SSH se ha cambiado del puerto predeterminado',
|
||||
@@ -4235,9 +4248,11 @@ const message = {
|
||||
rootLoginNormalDesc: 'El usuario root no puede iniciar sesión directamente',
|
||||
rootLoginRiskDesc: 'El usuario root puede iniciar sesión directamente. Se recomienda deshabilitarlo',
|
||||
passwordAuthNormalDesc: 'El inicio de sesión SSH por contraseña está deshabilitado',
|
||||
passwordAuthRiskDesc: 'El inicio de sesión por contraseña está permitido, aumentando el riesgo de fuerza bruta',
|
||||
passwordAuthRiskDesc:
|
||||
'El inicio de sesión por contraseña está permitido, aumentando el riesgo de fuerza bruta',
|
||||
keyAuthNormalDesc: 'La autenticación SSH por clave está habilitada',
|
||||
keyAuthRiskDesc: 'La autenticación por clave no está habilitada. Se recomienda usar inicio de sesión por clave',
|
||||
keyAuthRiskDesc:
|
||||
'La autenticación por clave no está habilitada. Se recomienda usar inicio de sesión por clave',
|
||||
websiteOverview: 'Resumen de sitios web',
|
||||
primaryDomain: 'Dominio principal',
|
||||
expireTime: 'Fecha de vencimiento',
|
||||
@@ -4277,7 +4292,8 @@ const message = {
|
||||
alertHealthAttention: 'Requiere atención',
|
||||
alertHealthRisk: 'Riesgo alto',
|
||||
alertHealthSummary: 'Estado de salud de alertas',
|
||||
alertHealthNormalReason: 'Tareas de alerta, canales de notificación y registros de ejecución están saludables',
|
||||
alertHealthNormalReason:
|
||||
'Tareas de alerta, canales de notificación y registros de ejecución están saludables',
|
||||
alertNoChannelReason: 'No hay canal de notificación de alerta habilitado',
|
||||
alertFailedLogReason: '{0} registros de fallos de alerta encontrados',
|
||||
alertPendingReason: '{0} registros de alerta pendientes de sincronización',
|
||||
@@ -4354,7 +4370,8 @@ const message = {
|
||||
viewHostMonitor: 'Ver monitoreo del host',
|
||||
systemHealthAttentionDesc:
|
||||
'{0} elementos de riesgo detectados en las últimas 24 horas. Priorice los picos de recursos y el uso de disco.',
|
||||
systemHealthNormalDesc: 'Las métricas de ejecución del host estuvieron normales en las últimas 24 horas',
|
||||
systemHealthNormalDesc:
|
||||
'Las métricas de ejecución del host estuvieron normales en las últimas 24 horas',
|
||||
monitorEnabled: 'Monitoreo habilitado',
|
||||
cpuCoreUsage: '{0} / {1} núcleos',
|
||||
load1Minute: 'Carga 1 min',
|
||||
@@ -4521,7 +4538,8 @@ const message = {
|
||||
savePath: 'Directorio de guardado',
|
||||
savePathRequired: 'Configure el directorio de guardado del informe',
|
||||
autoExport: 'Habilitar exportación automática',
|
||||
autoExportDesc: 'Generar automáticamente un informe de operaciones cada día a las 09:00 cuando esté habilitado',
|
||||
autoExportDesc:
|
||||
'Generar automáticamente un informe de operaciones cada día a las 09:00 cuando esté habilitado',
|
||||
autoExportEnabled: 'Exportación automática habilitada',
|
||||
autoExportDisabled: 'Exportación automática deshabilitada',
|
||||
readOnlyPermissionTip:
|
||||
|
||||
@@ -3805,6 +3805,10 @@ const message = {
|
||||
bindHelper: 'バインド - ファイアウォールルールは状態がバインドされている場合のみ有効になります。確認しますか?',
|
||||
unbindHelper:
|
||||
'アンバインド - アンバインドすると、追加されたすべてのファイアウォールルールが無効になります。注意して操作してください。確認しますか?',
|
||||
whiteList: 'ホワイトリスト',
|
||||
portWhiteList: 'ポートホワイトリスト',
|
||||
portWhiteListAlter: 'ファイアウォールの初期化または起動時に、ホワイトリスト内のポートは自動的に許可されます。',
|
||||
portWhiteListHelper: '80/tcp や 443/udp のようにプロトコルを指定できます。省略時は tcp が使用されます。',
|
||||
defaultStrategy: '現在のチェーン {0} のデフォルトポリシーは {1} です',
|
||||
defaultStrategy2:
|
||||
'現在のチェーン {0} のデフォルトポリシーは {1} です。現在の状態は未バインドです。追加されたファイアウォールルールはバインド後に有効になります!',
|
||||
@@ -4184,12 +4188,15 @@ const message = {
|
||||
'{0} 件のリスク設定を検出しました。ログインセキュリティを強化して侵入リスクを低減してください。',
|
||||
loginHealthNormalDesc: '現在のログインとSSHセキュリティ設定は正常です',
|
||||
loginHealthNormalReason: 'ログインセキュリティは正常です',
|
||||
securityEntranceConfiguredDesc: 'セキュリティエントランスが設定済みで、デフォルト入口の露出リスクを低減しています',
|
||||
securityEntranceRiskDesc: 'セキュリティエントランスが無効です。デフォルトのログイン入口を隠すことをお勧めします',
|
||||
securityEntranceConfiguredDesc:
|
||||
'セキュリティエントランスが設定済みで、デフォルト入口の露出リスクを低減しています',
|
||||
securityEntranceRiskDesc:
|
||||
'セキュリティエントランスが無効です。デフォルトのログイン入口を隠すことをお勧めします',
|
||||
allowIPsRestrictedDesc: 'パネルアクセス許可IPが制限されています',
|
||||
allowIPsRiskDesc: 'アクセスIPが制限されていません。公開環境では許可IPの設定をお勧めします',
|
||||
bindDomainRestrictedDesc: 'アクセスドメインがバインドされています',
|
||||
bindDomainRiskDesc: 'アクセスドメインがバインドされていません。固定ドメインへのアクセス制限をお勧めします',
|
||||
bindDomainRiskDesc:
|
||||
'アクセスドメインがバインドされていません。固定ドメインへのアクセス制限をお勧めします',
|
||||
accessRestrictionValue: '許可IP: {0} / バインドドメイン: {1}',
|
||||
accessRestrictionNormalDesc:
|
||||
'許可IPまたはバインドドメインが設定済みで、パネルアクセス元が制限されています',
|
||||
@@ -4198,8 +4205,7 @@ const message = {
|
||||
panelHTTPSNormalDesc: 'パネルHTTPSが有効です',
|
||||
panelHTTPSRiskDesc: 'パネルHTTPSが無効です。ログイン通信が平文で露出するリスクがあります',
|
||||
passwordComplexityNormalDesc: 'パスワード複雑性検証が有効です',
|
||||
passwordComplexityRiskDesc:
|
||||
'パスワード複雑性検証が無効で、弱パスワードのリスクが高いです',
|
||||
passwordComplexityRiskDesc: 'パスワード複雑性検証が無効で、弱パスワードのリスクが高いです',
|
||||
mfa: 'MFA 認証',
|
||||
mfaNormalDesc: 'MFA認証が有効で、ログインセキュリティが強化されています',
|
||||
mfaRiskDesc: 'MFA認証が無効です。多要素認証の有効化をお勧めします',
|
||||
@@ -4209,7 +4215,8 @@ const message = {
|
||||
passwordExpirationRiskDesc: 'パスワードが{0}日以内に期限切れになります。事前に対応してください',
|
||||
passwordExpirationExpiredDesc: 'パスワードが{0}日前に期限切れになりました。至急対応してください',
|
||||
sessionTimeoutNormalDesc: 'セッションタイムアウトは安全な範囲内です',
|
||||
sessionTimeoutRiskDesc: 'セッションタイムアウトが長めです。アイドルセッションの有効期間を制限することをお勧めします',
|
||||
sessionTimeoutRiskDesc:
|
||||
'セッションタイムアウトが長めです。アイドルセッションの有効期間を制限することをお勧めします',
|
||||
sshServiceNormalDesc: 'SSHサービスは正常に稼働しています',
|
||||
sshServiceRiskDesc: 'SSHサービスが未稼働または異常です',
|
||||
sshPortNormalDesc: 'SSHポートがデフォルトポートから変更済みです',
|
||||
|
||||
@@ -3718,6 +3718,10 @@ const message = {
|
||||
bindHelper: '바인딩 - 방화벽 규칙은 상태가 바인딩된 경우에만 효과가 있습니다. 확인하시겠습니까?',
|
||||
unbindHelper:
|
||||
'바인딩 해제 - 바인딩 해제 시 추가된 모든 방화벽 규칙이 무효화됩니다. 주의하여 진행하세요. 확인하시겠습니까?',
|
||||
whiteList: '화이트리스트',
|
||||
portWhiteList: '포트 화이트리스트',
|
||||
portWhiteListAlter: '방화벽을 초기화하거나 시작할 때 화이트리스트의 포트가 자동으로 허용됩니다.',
|
||||
portWhiteListHelper: '80/tcp 또는 443/udp처럼 프로토콜을 지정할 수 있습니다. 생략하면 기본값은 tcp입니다.',
|
||||
defaultStrategy: '현재 체인 {0}의 기본 정책은 {1}입니다',
|
||||
defaultStrategy2:
|
||||
'현재 체인 {0}의 기본 정책은 {1}입니다. 현재 상태는 바인딩되지 않았습니다. 추가된 방화벽 규칙은 바인딩 후에 효과가 발생합니다!',
|
||||
@@ -3952,8 +3956,7 @@ const message = {
|
||||
reportDate: '보고서 날짜',
|
||||
serverSecurityOverview: '서버 보안 운영 개요',
|
||||
securityScore: '보안 점수',
|
||||
overviewSummary:
|
||||
'현재 보안 등급: {0}. 총 감점 {1}점, {2}개 위험 항목 발견, {3}개 검사 대상 포함.',
|
||||
overviewSummary: '현재 보안 등급: {0}. 총 감점 {1}점, {2}개 위험 항목 발견, {3}개 검사 대상 포함.',
|
||||
riskDistribution: '위험 분포',
|
||||
totalDeducted: '총 감점',
|
||||
noRiskDeducted: '미감점',
|
||||
@@ -4092,8 +4095,7 @@ const message = {
|
||||
recent24Hours: '최근 24시간',
|
||||
currentService: '현재 서비스',
|
||||
riskItemsExist: '{0}개 위험 항목 존재',
|
||||
loginHealthRiskDesc:
|
||||
'{0}개의 위험 설정이 감지되었습니다. 로그인 보안을 강화하여 침입 위험을 낮추세요.',
|
||||
loginHealthRiskDesc: '{0}개의 위험 설정이 감지되었습니다. 로그인 보안을 강화하여 침입 위험을 낮추세요.',
|
||||
loginHealthNormalDesc: '현재 로그인 및 SSH 보안 설정이 정상 상태입니다',
|
||||
loginHealthNormalReason: '로그인 보안 설정 정상',
|
||||
securityEntranceConfiguredDesc: '보안 입구가 구성되어 기본 입구 노출 위험이 감소됩니다',
|
||||
|
||||
@@ -3857,6 +3857,12 @@ const message = {
|
||||
bindHelper: 'Ikat - Peraturan firewall hanya akan berkuat kuasa apabila status terikat. Sahkan?',
|
||||
unbindHelper:
|
||||
'Nyahikat - Apabila tidak terikat, semua peraturan firewall yang ditambah akan menjadi tidak sah. Teruskan dengan berhati-hati. Sahkan?',
|
||||
whiteList: 'Senarai putih',
|
||||
portWhiteList: 'Senarai putih port',
|
||||
portWhiteListAlter:
|
||||
'Port dalam senarai putih akan dibuka secara automatik apabila firewall dimulakan atau dihidupkan.',
|
||||
portWhiteListHelper:
|
||||
'Protokol boleh ditentukan, contohnya 80/tcp atau 443/udp. Jika diabaikan, tcp digunakan secara lalai.',
|
||||
defaultStrategy: 'Dasar lalai untuk rantaian semasa {0} adalah {1}',
|
||||
defaultStrategy2:
|
||||
'Dasar lalai untuk rantaian semasa {0} adalah {1}, status semasa adalah tidak terikat. Peraturan firewall yang ditambah akan berkuat kuasa selepas pengikatan!',
|
||||
@@ -4239,8 +4245,10 @@ const message = {
|
||||
'{0} konfigurasi berisiko dikesan. Kukuhkan keselamatan log masuk untuk mengurangkan risiko pencerobohan.',
|
||||
loginHealthNormalDesc: 'Konfigurasi keselamatan log masuk dan SSH semasa adalah normal',
|
||||
loginHealthNormalReason: 'Keselamatan log masuk adalah normal',
|
||||
securityEntranceConfiguredDesc: 'Pintu masuk keselamatan dikonfigurasi untuk mengurangkan pendedahan laluan lalai',
|
||||
securityEntranceRiskDesc: 'Pintu masuk keselamatan tidak didayakan. Sembunyikan pintu masuk log masuk lalai',
|
||||
securityEntranceConfiguredDesc:
|
||||
'Pintu masuk keselamatan dikonfigurasi untuk mengurangkan pendedahan laluan lalai',
|
||||
securityEntranceRiskDesc:
|
||||
'Pintu masuk keselamatan tidak didayakan. Sembunyikan pintu masuk log masuk lalai',
|
||||
allowIPsRestrictedDesc: 'IP dibenarkan dihadkan untuk akses panel',
|
||||
allowIPsRiskDesc: 'IP akses tidak dihadkan. Konfigurasikan IP dibenarkan untuk persekitaran awam',
|
||||
bindDomainRestrictedDesc: 'Domain akses telah diikat',
|
||||
|
||||
@@ -3993,6 +3993,12 @@ const message = {
|
||||
'Vincular - As regras de firewall só entrarão em vigor quando o status estiver vinculado. Confirmar?',
|
||||
unbindHelper:
|
||||
'Desvincular - Quando desvinculado, todas as regras de firewall adicionadas se tornarão inválidas. Prossiga com cautela. Confirmar?',
|
||||
whiteList: 'Lista branca',
|
||||
portWhiteList: 'Lista branca de portas',
|
||||
portWhiteListAlter:
|
||||
'As portas na lista branca serão abertas automaticamente ao inicializar ou iniciar o firewall.',
|
||||
portWhiteListHelper:
|
||||
'O protocolo pode ser especificado, por exemplo 80/tcp ou 443/udp. Se omitido, o padrão é tcp.',
|
||||
defaultStrategy: 'A política padrão para a cadeia atual {0} é {1}',
|
||||
defaultStrategy2:
|
||||
'A política padrão para a cadeia atual {0} é {1}, o status atual é não vinculado. As regras de firewall adicionadas entrarão em vigor após a vinculação!',
|
||||
@@ -4378,7 +4384,8 @@ const message = {
|
||||
'{0} configurações de risco detectadas. Fortaleça a segurança de login para reduzir o risco de invasão.',
|
||||
loginHealthNormalDesc: 'As configurações atuais de login e segurança SSH estão normais',
|
||||
loginHealthNormalReason: 'Segurança de login está normal',
|
||||
securityEntranceConfiguredDesc: 'Entrada de segurança configurada para reduzir a exposição da entrada padrão',
|
||||
securityEntranceConfiguredDesc:
|
||||
'Entrada de segurança configurada para reduzir a exposição da entrada padrão',
|
||||
securityEntranceRiskDesc: 'Entrada de segurança desativada. Oculte a entrada de login padrão',
|
||||
allowIPsRestrictedDesc: 'IPs autorizados estão restritos para acesso ao painel',
|
||||
allowIPsRiskDesc: 'IPs de acesso sem restrição. Configure IPs autorizados para ambientes públicos',
|
||||
@@ -4445,7 +4452,8 @@ const message = {
|
||||
alertHealthAttention: 'Atenção necessária',
|
||||
alertHealthRisk: 'Alto risco',
|
||||
alertHealthSummary: 'Saúde do alerta',
|
||||
alertHealthNormalReason: 'Tarefas de alerta, canais de notificação e registros de execução estão saudáveis',
|
||||
alertHealthNormalReason:
|
||||
'Tarefas de alerta, canais de notificação e registros de execução estão saudáveis',
|
||||
alertNoChannelReason: 'Nenhum canal de notificação está ativado',
|
||||
alertFailedLogReason: '{0} registros de alerta com falha encontrados',
|
||||
alertPendingReason: '{0} registros de alerta pendentes de sincronização',
|
||||
|
||||
@@ -3848,6 +3848,11 @@ const message = {
|
||||
bindHelper: 'Привязать - Правила брандмауэра вступят в силу только когда статус привязан. Подтвердить?',
|
||||
unbindHelper:
|
||||
'Отвязать - При отвязке все добавленные правила брандмауэра станут недействительными. Действуйте осторожно. Подтвердить?',
|
||||
whiteList: 'Белый список',
|
||||
portWhiteList: 'Белый список портов',
|
||||
portWhiteListAlter:
|
||||
'Порты из белого списка будут автоматически открыты при инициализации или запуске брандмауэра.',
|
||||
portWhiteListHelper: 'Можно указать протокол, например 80/tcp или 443/udp. Если не указано, используется tcp.',
|
||||
defaultStrategy: 'Политика по умолчанию для текущей цепочки {0} - {1}',
|
||||
defaultStrategy2:
|
||||
'Политика по умолчанию для текущей цепочки {0} - {1}, текущий статус - не привязан. Добавленные правила брандмауэра вступят в силу после привязки!',
|
||||
@@ -4230,7 +4235,8 @@ const message = {
|
||||
'Обнаружено {0} рисковых настроек. Рекомендуется усилить безопасность входа для снижения риска вторжения.',
|
||||
loginHealthNormalDesc: 'Текущие настройки безопасности входа и SSH в норме',
|
||||
loginHealthNormalReason: 'Настройки безопасности входа в норме',
|
||||
securityEntranceConfiguredDesc: 'Безопасный вход настроен, снижается риск раскрытия стандартной точки входа',
|
||||
securityEntranceConfiguredDesc:
|
||||
'Безопасный вход настроен, снижается риск раскрытия стандартной точки входа',
|
||||
securityEntranceRiskDesc: 'Безопасный вход не включён. Рекомендуется скрыть стандартную точку входа',
|
||||
allowIPsRestrictedDesc: 'Доступ к панели ограничен по IP-адресам',
|
||||
allowIPsRiskDesc: 'Доступ по IP не ограничен. Для публичных сред рекомендуется настроить доверенные IP',
|
||||
@@ -4252,10 +4258,12 @@ const message = {
|
||||
passwordExpiration: 'Срок действия пароля',
|
||||
passwordExpirationNormalDesc: 'Срок действия пароля находится в безопасном диапазоне',
|
||||
passwordExpirationUnsetDesc: 'Срок действия пароля не задан, рекомендуется скорее настроить',
|
||||
passwordExpirationRiskDesc: 'Срок действия пароля истекает через {0} дней, рекомендуется заблаговременно продлить',
|
||||
passwordExpirationRiskDesc:
|
||||
'Срок действия пароля истекает через {0} дней, рекомендуется заблаговременно продлить',
|
||||
passwordExpirationExpiredDesc: 'Срок действия пароля истёк {0} дней назад, продлите как можно скорее',
|
||||
sessionTimeoutNormalDesc: 'Тайм-аут сессии находится в безопасном диапазоне',
|
||||
sessionTimeoutRiskDesc: 'Тайм-аут сессии слишком велик. Рекомендуется ограничить срок неактивных сессий',
|
||||
sessionTimeoutRiskDesc:
|
||||
'Тайм-аут сессии слишком велик. Рекомендуется ограничить срок неактивных сессий',
|
||||
sshServiceNormalDesc: 'Служба SSH работает нормально',
|
||||
sshServiceRiskDesc: 'Служба SSH не работает или находится в аномальном состоянии',
|
||||
sshPortNormalDesc: 'SSH-порт изменён с порта по умолчанию',
|
||||
|
||||
@@ -3849,6 +3849,12 @@ const message = {
|
||||
bindHelper: 'Bağla - Güvenlik duvarı kuralları yalnızca durum bağlı olduğunda etkili olur. Onaylıyor musunuz?',
|
||||
unbindHelper:
|
||||
'Bağlantıyı Kaldır - Bağlantı kaldırıldığında, eklenen tüm güvenlik duvarı kuralları geçersiz olacaktır. Dikkatli ilerleyin. Onaylıyor musunuz?',
|
||||
whiteList: 'Beyaz liste',
|
||||
portWhiteList: 'Port beyaz listesi',
|
||||
portWhiteListAlter:
|
||||
'Beyaz listedeki portlar, güvenlik duvarı başlatılırken veya çalıştırılırken otomatik olarak açılır.',
|
||||
portWhiteListHelper:
|
||||
'Protokol belirtilebilir, örn. 80/tcp veya 443/udp. Belirtilmezse varsayılan tcp kullanılır.',
|
||||
defaultStrategy: 'Mevcut zincir {0} için varsayılan politika {1}',
|
||||
defaultStrategy2:
|
||||
'Mevcut zincir {0} için varsayılan politika {1}, mevcut durum bağlı değil. Eklenen güvenlik duvarı kuralları bağlandıktan sonra etkili olacak!',
|
||||
@@ -4113,7 +4119,7 @@ const message = {
|
||||
scoreSSHLoginFailedHigh: 'SSH girişi {0} kez başarısız oldu',
|
||||
scoreSSHLoginFailedMedium: 'SSH girişi {0} kez başarısız oldu',
|
||||
scoreMFADisabled: 'MFA devre dışı',
|
||||
scoreAllowIPsOpen: 'İzin verilen IP\'ler ve bağlı alan adı yapılandırılmamış veya erişim kısıtlanmamış',
|
||||
scoreAllowIPsOpen: "İzin verilen IP'ler ve bağlı alan adı yapılandırılmamış veya erişim kısıtlanmamış",
|
||||
scorePasswordExpired: 'Panel şifresi süresi dolmuş',
|
||||
scorePasswordExpiring: 'Panel şifresi {0} gün içinde sona eriyor',
|
||||
scorePanelHTTPSDisabled: 'Panel HTTPS devre dışı',
|
||||
@@ -4196,7 +4202,7 @@ const message = {
|
||||
notConfigured: 'Yapılandırılmamış',
|
||||
normal: 'Normal',
|
||||
needAttention: 'Dikkat Gerekli',
|
||||
allowIPs: 'İzin Verilen IP\'ler',
|
||||
allowIPs: "İzin Verilen IP'ler",
|
||||
restricted: 'Kısıtlanmış',
|
||||
unrestricted: 'Kısıtlanmamış',
|
||||
bindDomain: 'Bağlı Alan Adı',
|
||||
@@ -4231,22 +4237,22 @@ const message = {
|
||||
'{0} riskli yapılandırma algılandı. Saldırı riskini azaltmak için giriş güvenliğini güçlendirin.',
|
||||
loginHealthNormalDesc: 'Mevcut giriş ve SSH güvenlik yapılandırmaları normal durumda',
|
||||
loginHealthNormalReason: 'Giriş güvenliği normal',
|
||||
securityEntranceConfiguredDesc: 'Güvenlik girişi yapılandırılmış, varsayılan giriş maruziyeti azaltılmış',
|
||||
securityEntranceConfiguredDesc:
|
||||
'Güvenlik girişi yapılandırılmış, varsayılan giriş maruziyeti azaltılmış',
|
||||
securityEntranceRiskDesc: 'Güvenlik girişi devre dışı. Varsayılan giriş girişini gizleyin',
|
||||
allowIPsRestrictedDesc: 'Panel erişimi için izin verilen IP\'ler kısıtlanmış',
|
||||
allowIPsRiskDesc: 'Erişim IP\'leri kısıtlanmamış. Genel ortamlar için izin verilen IP\'leri yapılandırın',
|
||||
allowIPsRestrictedDesc: "Panel erişimi için izin verilen IP'ler kısıtlanmış",
|
||||
allowIPsRiskDesc: "Erişim IP'leri kısıtlanmamış. Genel ortamlar için izin verilen IP'leri yapılandırın",
|
||||
bindDomainRestrictedDesc: 'Erişim alan adı bağlanmış',
|
||||
bindDomainRiskDesc: 'Erişim alan adı bağlanmamış. Erişimi sabit bir alan adıyla kısıtlayın',
|
||||
accessRestrictionValue: 'İzin verilen IP\'ler: {0} / Bağlı alan adı: {1}',
|
||||
accessRestrictionValue: "İzin verilen IP'ler: {0} / Bağlı alan adı: {1}",
|
||||
accessRestrictionNormalDesc:
|
||||
'Panel erişim kaynaklarını kısıtlamak için izin verilen IP\'ler veya bağlı alan adı yapılandırılmış',
|
||||
"Panel erişim kaynaklarını kısıtlamak için izin verilen IP'ler veya bağlı alan adı yapılandırılmış",
|
||||
accessRestrictionRiskDesc:
|
||||
'İzin verilen IP\'ler ve bağlı alan adı yapılandırılmamış veya erişim kısıtlanmamış. En az birini yapılandırın',
|
||||
"İzin verilen IP'ler ve bağlı alan adı yapılandırılmamış veya erişim kısıtlanmamış. En az birini yapılandırın",
|
||||
panelHTTPSNormalDesc: 'Panel HTTPS etkin',
|
||||
panelHTTPSRiskDesc: 'Panel HTTPS devre dışı. Giriş trafiği açığa çıkabilir',
|
||||
passwordComplexityNormalDesc: 'Şifre karmaşıklık doğrulaması etkin',
|
||||
passwordComplexityRiskDesc:
|
||||
'Şifre karmaşıklık doğrulaması devre dışı, zayıf şifre riski yüksek',
|
||||
passwordComplexityRiskDesc: 'Şifre karmaşıklık doğrulaması devre dışı, zayıf şifre riski yüksek',
|
||||
sessionTimeoutNormalDesc: 'Oturum zaman aşımı güvenli aralıkta',
|
||||
sessionTimeoutRiskDesc: 'Oturum zaman aşımı uzun. Boş oturum geçerlilik süresini kısıtlayın',
|
||||
sshServiceNormalDesc: 'SSH servisi normal çalışıyor',
|
||||
@@ -4399,7 +4405,7 @@ const message = {
|
||||
'{0} risk öğesi algılandı. Web sitesi güvenliğini ve kullanılabilirliğini korumak için yakında ele alın.',
|
||||
websiteHealthNormalDesc: 'Mevcut web sitesi koruma metrikleri normal',
|
||||
handleSslRisk: 'Sertifika Risklerini Ele Al',
|
||||
viewWaf: 'WAF\'ı Gör',
|
||||
viewWaf: "WAF'ı Gör",
|
||||
priority: 'Öncelik',
|
||||
riskDescription: 'Risk Açıklaması',
|
||||
deductScore: 'Düşülen Puan',
|
||||
@@ -4514,14 +4520,14 @@ const message = {
|
||||
checkBackupTasks: 'Yedek Görevlerini Kontrol Et',
|
||||
generationRule: 'Oluşturma Kuralları',
|
||||
scheduleDaily: 'Günlük',
|
||||
scheduleDailyDesc: 'Her gün 09:00\'da son 24 saatin raporunu oluştur',
|
||||
scheduleDailyDesc: "Her gün 09:00'da son 24 saatin raporunu oluştur",
|
||||
scheduleWeekly: 'Haftalık',
|
||||
scheduleWeeklyDesc: 'Her Pazartesi 09:00\'da son 7 günün raporunu oluştur',
|
||||
scheduleWeeklyDesc: "Her Pazartesi 09:00'da son 7 günün raporunu oluştur",
|
||||
scheduleMonthly: 'Aylık',
|
||||
scheduleMonthlyDesc: 'Her ayın 1\'inde 09:00\'da bir önceki ayın raporunu oluştur',
|
||||
scheduleCurrentDaily: 'Her gün 09:00\'da son 24 saatin raporu oluşturulur · Sonraki {0}',
|
||||
scheduleCurrentWeekly: 'Her Pazartesi 09:00\'da son 7 günün raporu oluşturulur · Sonraki {0}',
|
||||
scheduleCurrentMonthly: 'Her ayın 1\'inde 09:00\'da bir önceki ayın raporu oluşturulur · Sonraki {0}',
|
||||
scheduleMonthlyDesc: "Her ayın 1'inde 09:00'da bir önceki ayın raporunu oluştur",
|
||||
scheduleCurrentDaily: "Her gün 09:00'da son 24 saatin raporu oluşturulur · Sonraki {0}",
|
||||
scheduleCurrentWeekly: "Her Pazartesi 09:00'da son 7 günün raporu oluşturulur · Sonraki {0}",
|
||||
scheduleCurrentMonthly: "Her ayın 1'inde 09:00'da bir önceki ayın raporu oluşturulur · Sonraki {0}",
|
||||
notificationMethod: 'Bildirim Yöntemleri',
|
||||
channel: 'Kanal',
|
||||
receiver: 'Alıcı',
|
||||
@@ -4542,7 +4548,7 @@ const message = {
|
||||
savePath: 'Kayıt Dizini',
|
||||
savePathRequired: 'Rapor kayıt dizinini ayarlayın',
|
||||
autoExport: 'Otomatik Dışa Aktarmayı Etkinleştir',
|
||||
autoExportDesc: 'Etkinleştirildiğinde her gün 09:00\'da otomatik olarak operasyon raporu oluşturulur',
|
||||
autoExportDesc: "Etkinleştirildiğinde her gün 09:00'da otomatik olarak operasyon raporu oluşturulur",
|
||||
autoExportEnabled: 'Otomatik dışa aktarma etkin',
|
||||
autoExportDisabled: 'Otomatik dışa aktarma devre dışı',
|
||||
readOnlyPermissionTip:
|
||||
|
||||
@@ -3506,6 +3506,10 @@ const message = {
|
||||
initHelper: '偵測到 {0} 未初始化,請點選頂部狀態列的初始化按鈕進行設定',
|
||||
bindHelper: '綁定 僅當狀態為綁定時,防火牆規則才能生效,是否確認?',
|
||||
unbindHelper: '解除綁定 解除綁定時,已新增的所有防火牆規則將失效,請謹慎操作,是否確認?',
|
||||
whiteList: '白名單',
|
||||
portWhiteList: '埠白名單',
|
||||
portWhiteListAlter: '防火牆初始化或啟動時,將自動放行白名單埠',
|
||||
portWhiteListHelper: '支援指定協定(如 80/tcp、443/udp),未指定時預設使用 tcp。',
|
||||
defaultStrategy: '目前鏈 {0} 的預設策略為 {1}',
|
||||
defaultStrategy2: '目前鏈 {0} 的預設策略為 {1},當前狀態為未綁定,已新增的防火牆規則需要綁定後生效',
|
||||
filterRule: 'Filter 規則',
|
||||
|
||||
@@ -3498,6 +3498,9 @@ const message = {
|
||||
initHelper: '检测到 {0} 未初始化,请点击顶部状态栏的初始化按钮进行配置!',
|
||||
bindHelper: '绑定 仅当状态为绑定时,防火墙规则才能生效,是否确认?',
|
||||
unbindHelper: '解绑 解除绑定时,已添加的所有防火墙规则将失效,请谨慎操作,是否确认?',
|
||||
portWhiteList: '端口白名单',
|
||||
portWhiteListAlter: '防火墙初始化或启动时,将自动放行白名单端口',
|
||||
portWhiteListHelper: '支持指定协议(如 80/tcp、443/udp),未指定时默认使用 TCP。',
|
||||
defaultStrategy: '当前链 {0} 的默认策略为 {1}',
|
||||
defaultStrategy2: '当前链 {0} 的默认策略为 {1},当前状态为未绑定,已添加的防火墙规则需要绑定后生效!',
|
||||
filterRule: 'Filter 规则',
|
||||
|
||||
@@ -46,6 +46,9 @@
|
||||
<el-button v-permission type="primary" @click="onOpenDialog('create')">
|
||||
{{ $t('commons.button.create') }}
|
||||
</el-button>
|
||||
<el-button v-permission @click="onOpenWhiteList" plain>
|
||||
{{ $t('firewall.portWhiteList') }}
|
||||
</el-button>
|
||||
<el-button v-permission @click="onDelete(null)" plain :disabled="selects.length === 0">
|
||||
{{ $t('commons.button.delete') }}
|
||||
</el-button>
|
||||
@@ -158,6 +161,7 @@
|
||||
<OperateDialog @search="search" ref="dialogRef" />
|
||||
<ImportDialog @search="search" ref="dialogImportRef" />
|
||||
<ProcessDetail ref="processDetailRef" />
|
||||
<WhiteList ref="whiteListRef" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -165,6 +169,7 @@
|
||||
import FireRouter from '@/views/host/firewall/index.vue';
|
||||
import OperateDialog from '@/views/host/firewall/port/operate/index.vue';
|
||||
import ImportDialog from '@/views/host/firewall/port/import/index.vue';
|
||||
import WhiteList from '@/views/host/firewall/port/white-list/index.vue';
|
||||
import FireStatus from '@/views/host/firewall/status/index.vue';
|
||||
import ProcessDetail from '@/views/host/process/process/detail/index.vue';
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
@@ -194,6 +199,7 @@ const fireStatusRef = ref();
|
||||
const opRef = ref();
|
||||
const dialogImportRef = ref();
|
||||
const processDetailRef = ref();
|
||||
const whiteListRef = ref();
|
||||
|
||||
const listeningProcesses = ref<Process.ListeningProcess[]>([]);
|
||||
|
||||
@@ -398,6 +404,10 @@ const onImport = () => {
|
||||
dialogImportRef.value.acceptParams();
|
||||
};
|
||||
|
||||
const onOpenWhiteList = () => {
|
||||
whiteListRef.value.acceptParams();
|
||||
};
|
||||
|
||||
const onExport = () => {
|
||||
ElMessageBox.confirm(
|
||||
i18n.global.t('firewall.exportHelper', [selects.value.length]),
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
<template>
|
||||
<DrawerPro v-model="drawerVisible" :header="$t('firewall.portWhiteList')" @close="handleClose" size="small">
|
||||
<template #content>
|
||||
<el-alert type="info" :closable="false" :title="$t('firewall.portWhiteListAlter')" />
|
||||
|
||||
<el-button class="mt-5" type="primary" @click="openCreate">
|
||||
{{ $t('commons.button.add') }}
|
||||
</el-button>
|
||||
<ComplexTable :data="data" v-loading="loading">
|
||||
<el-table-column :label="$t('commons.table.port')" prop="port">
|
||||
<template #default="{ row }">
|
||||
<span v-if="!row.edit">{{ row.port }}</span>
|
||||
<el-input v-else v-model.trim="row.port" placeholder="80/tcp" clearable />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('commons.table.operate')" width="160">
|
||||
<template #default="{ row, $index }">
|
||||
<el-button v-if="row.edit" link type="primary" @click="saveRow(row)">
|
||||
{{ $t('commons.button.save') }}
|
||||
</el-button>
|
||||
<el-button v-if="!row.edit" link type="primary" @click="editRow(row)">
|
||||
{{ $t('commons.button.edit') }}
|
||||
</el-button>
|
||||
<el-button v-if="!row.edit" link type="primary" @click="removeRow($index)">
|
||||
{{ $t('commons.button.delete') }}
|
||||
</el-button>
|
||||
<el-button v-if="row.edit" link type="primary" @click="cancelEdit(row, $index)">
|
||||
{{ $t('commons.button.cancel') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</ComplexTable>
|
||||
<span class="input-help">{{ $t('firewall.portWhiteListHelper') }}</span>
|
||||
</template>
|
||||
<template #footer>
|
||||
<el-button @click="drawerVisible = false">{{ $t('commons.button.cancel') }}</el-button>
|
||||
<el-button :loading="loading" type="primary" @click="onSubmit">
|
||||
{{ $t('commons.button.confirm') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</DrawerPro>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import { getAgentSettingInfo, updateAgentSetting } from '@/api/modules/setting';
|
||||
import i18n from '@/lang';
|
||||
import { MsgError, MsgSuccess } from '@/utils/message';
|
||||
import { checkPort } from '@/utils/validate';
|
||||
|
||||
interface WhiteListItem {
|
||||
port: string;
|
||||
oldPort: string;
|
||||
edit: boolean;
|
||||
isNew: boolean;
|
||||
}
|
||||
const emit = defineEmits<{ (e: 'search'): void }>();
|
||||
|
||||
const drawerVisible = ref(false);
|
||||
const loading = ref(false);
|
||||
const data = ref<WhiteListItem[]>([]);
|
||||
const defaultWhiteList = '80/tcp,443/tcp,443/udp';
|
||||
|
||||
const acceptParams = async (): Promise<void> => {
|
||||
drawerVisible.value = true;
|
||||
loading.value = true;
|
||||
await getAgentSettingInfo()
|
||||
.then((res) => {
|
||||
data.value = parseWhiteList(res.data.firewallPortWhiteList ?? defaultWhiteList);
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
const parseWhiteList = (value: string): WhiteListItem[] => {
|
||||
return value
|
||||
.split(/[\s,;]+/)
|
||||
.filter((item) => item !== '')
|
||||
.map((item) => ({
|
||||
port: item,
|
||||
oldPort: item,
|
||||
edit: false,
|
||||
isNew: false,
|
||||
}));
|
||||
};
|
||||
|
||||
const openCreate = () => {
|
||||
for (const item of data.value) {
|
||||
if (item.isNew && item.port === '') {
|
||||
return;
|
||||
}
|
||||
}
|
||||
data.value.unshift({
|
||||
port: '',
|
||||
oldPort: '',
|
||||
edit: true,
|
||||
isNew: true,
|
||||
});
|
||||
};
|
||||
|
||||
const editRow = (row: WhiteListItem) => {
|
||||
row.oldPort = row.port;
|
||||
row.edit = true;
|
||||
};
|
||||
|
||||
const saveRow = (row: WhiteListItem) => {
|
||||
if (!validatePort(row.port)) {
|
||||
return;
|
||||
}
|
||||
row.port = normalizePort(row.port);
|
||||
row.oldPort = row.port;
|
||||
row.edit = false;
|
||||
row.isNew = false;
|
||||
};
|
||||
|
||||
const cancelEdit = (row: WhiteListItem, index: number) => {
|
||||
if (row.isNew) {
|
||||
data.value.splice(index, 1);
|
||||
return;
|
||||
}
|
||||
row.port = row.oldPort;
|
||||
row.edit = false;
|
||||
};
|
||||
|
||||
const removeRow = (index: number) => {
|
||||
data.value.splice(index, 1);
|
||||
};
|
||||
|
||||
const normalizePort = (value: string): string => {
|
||||
const segments = value.split('/');
|
||||
const port = segments[0];
|
||||
const protocol = segments[1] ? segments[1].toLowerCase() : '';
|
||||
return protocol ? `${port}/${protocol}` : port;
|
||||
};
|
||||
|
||||
const validatePort = (value: string): boolean => {
|
||||
if (value === '') {
|
||||
MsgError(i18n.global.t('firewall.portFormatError'));
|
||||
return false;
|
||||
}
|
||||
const segments = value.split('/');
|
||||
const [port, protocol = 'tcp'] = segments;
|
||||
if (checkPort(port) || !['tcp', 'udp'].includes(protocol.toLowerCase()) || segments.length > 2) {
|
||||
MsgError(i18n.global.t('firewall.portFormatError'));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
const onSubmit = async () => {
|
||||
const ports = data.value.map((item) => item.port).filter((item) => item !== '');
|
||||
for (const port of ports) {
|
||||
if (!validatePort(port)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
loading.value = true;
|
||||
await updateAgentSetting({
|
||||
key: 'FirewallPortWhiteList',
|
||||
value: ports.map((item) => normalizePort(item)).join('\n'),
|
||||
})
|
||||
.then(() => {
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
emit('search');
|
||||
drawerVisible.value = false;
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
drawerVisible.value = false;
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
acceptParams,
|
||||
});
|
||||
</script>
|
||||
Reference in New Issue
Block a user