整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

「运维」记录一起网站劫持事件

「运维」记录一起网站劫持事件

事很短,处理也简单。权当记录一下,各位安全大大们手下留情。

最近一位客户遇到官网被劫持的情况,想我们帮忙解决一下(本来不关我们的事,毕竟情面在这...还是无偿地协助一下),经过三四轮“谦让”最终这个任务还是落到了我这个不精通安全的人的头上()。

客户说通过百度跳转官网,首页加载到一半时发生另一次跳转,跳到一个“赌球”网站去(欧洲杯最近大热),但直接输入域名就不会发生跳转。

我初步尝试了一下,除了 PC 端有这种情况外,移动端也会触发这种跳转...首先不要被现象迷惑,从首页能够加载到一半的情况可知,这种恶意跳转应该是通过代码触发的。

因为如果是在网络层面又或者 Http Server 转发,根本就不会让官网首页出现,因此排查的方向应聚焦到代码层面。

其次,通过百度访问会触发恶意跳转,但域名访问不会。这不禁让我想到对方有可能是通过 Header 中的 Referer 进行来源判断。于是我尝试使用 bing 搜索引擎对官网进行访问,结果证实了我的想法,在 bing 访问是不会发生跳转的。

好了,既然是通过代码跳转的,那么它总要发生请求吧。究竟是从哪发生的请求呢?

为了防止跳转过快的情况,先在百度页面中复制一个链接,打开一个新的窗口并且打开开发者模式,再将链接复制到浏览器进行访问。如下图:

这时候就能够将首次访问的所有请求获取到,并且在准备发生自动跳转之前你有足够的时间来取消页面请求,就能够得到上图的输出。通过上图的网络输出可知,其他都是正常的官网请求,唯独 data.joysoo.xyz 是一个不知来路的域名。而且请求的 JavaScript 文件也足够可疑,连名字都是经过加密的样子。

嗯...在截获了当前的信息后,让其跳转看看还有什么网络输出,如下图:

噢,这个网站也尝试加载 data.joysoo.xyz 的 DL1iBa6yb(这里与官网的 JavaScript 已经不一样了)。至此,从信息层面能够通过 data.joysoo.xyz 域名可以将两个网站的关联串联起来了,那么接下来就可通过这个域名进行代码搜索。

将客户网站的 PHP 代码放入 VSCode 中进行全局搜索。如下图:

这个域名恰巧只有一个 php 文件匹配成功。从这里也可以看出为什么无论从哪个页面跳转都会进行恶意跳转,因为这个脚本是直接植入到页面的 ICP banner 模块中的,而由于 ICP banner 每个页面都内嵌的,因此无论哪个页面都会发生跳转。

那么这个脚本是从哪里植入的呢?

从上图可知,在 log 文件中也找到两条与这个域名相关的记录,如下图:

呃...这里有一条 update 语句将这个脚本写入到数据库里面,估计是被 SQL注入了吧。

至此,整个解决思路也形成了。由于当前的 PHP 框架会在网页访问时自动生成新的页面,因此只需要重新更新数据库内容即可恢复。但是,这样也只是治标不治本,最最重要的还是加强对云服务器以及应用的防护才是重中之重,不然问题还是会重新出现。

菜鸟入门,各位大佬轻喷,如有谬误之处欢迎讨论建议,也欢迎各位道友与我同行

"不积跬步,无以至千里;不积小流,无以成江海"

继续

续接上篇文章,我们实现了一个简单的登陆界面,但是我们的表单提示,例如用户名等,是用的文字在按钮上方提示的

那我们如何去实现一个提示框用于提示呢?然后再自动聚焦到输入框中呢?

提示框的实现

// 是否显示弹窗的标识
@State private var showAlert:Bool=false;

// 在登陆按钮之后放置弹窗
Button("登陆"){
    // 切换要显示Alert
    showAlert.toggle();
    // 省略一部分操作。。。
}.alert(isPresented: $showAlert){ // 这里 isPresented 绑定 showAlert变量
    Alert(
        title: Text("提示"), // 顶部的标题
        message: Text(res), // 弹窗的内容,需要是一个Text,调用了我们之前定义的提示文本
        primaryButton: .default(Text("取消")){// 第一个按钮是默认类型样式,显示取消
            // 第一个按钮点击后的操作
        },
        secondaryButton: .destructive(Text("确定")){
        
        }
    )
}

以上的代码运行后得到如下结果

在这里插入图片描述

focus 到TextField

以上的弹出框提示已经解决,那么接下来需要实现的是弹出之后哪一个字段没填,就让它自动聚焦,让用户可以直接填写那个字段 添加如下的代码

// 是否聚焦到用户名字段,注意@符号后面跟的是 FocusState,不然用到focused里面会报错,并且不能设置默认值
@FocusState private var focusUser:Bool;
HStack{
    Text("用户名")
    Spacer()
    TextField("请输入用户名",text:$userName)
        .multilineTextAlignment(.center)
        // 给用户名字段的 focused 绑定 focusUser 变量
        .focused($focusUser)
    }.padding(.all)
}
/// ... 省略部分代码
Button("登陆"){
    // 切换要显示Alert
    showAlert.toggle();
    if(userName==""){
        // 如果没填 userName 那么切换 focusUser 的值
        focusUser.toggle()
    }
    // 省略一部分操作。。。
}
// 。。。 省略Alert部分

此处的代码实现了,如果在点击登陆按钮后用户名没有填,自动聚焦到用户名字段

在本页面中,共有三个字段,可以定义三个变量的形式来进行判定聚焦

但是如果有很多个字段的话就不合适了,我们可以使用枚举的方式来进行定义

以下贴出本页面完整的代码

import SwiftUI

struct ContentView: View {
    // 用户名
    @State private var userName:String="";
    // 密码
    @State private var passWord:String="";
    // 验证码
    @State private var code:String="";
    // 提示语
    @State private var res:String="请输入。。。";
    // 提示语的颜色,color类型
    @State private var color:Color=.red;
    
    // 是否显示弹窗标识
    @State private var showAlert:Bool=false;
    
    // 聚焦到哪一个字段?
    @FocusState private var focus:FocusField?;
    
    // 定义一个 Hashable 的枚举,因为 focused 的第二个参数需要一个hashable的参数
    enum FocusField:Hashable{
        case name;
        case password;
        case code;
        case clear;
    };
    
    var body: some View {
        // 整体纵向布局
        VStack {
            // 页面标题,加粗,标题字体
            Text("登陆界面").fontWeight(.bold).font(.title)
            // 分隔占位,有点类似html中flex的flex:1,具体怎么用之后再看
            Spacer()
            // 一个横向布局,表单项名称-分隔占位-以及表单项
            // 给一个 .all 的 padding,不然不好看
            HStack{
                Text("用户名")
                Spacer()
                TextField("请输入用户名",text:$userName)
                    .multilineTextAlignment(.center)
                    // focused 绑定 focus变量,当该变量为 .name 时
                    .focused($focus,equals: .name)
            }.padding(.all)
            
            HStack{
                Text("密码")
                Spacer()
                // secure field 跟 TextField基本类似,只是隐藏输入的内容
                SecureField("请输入密码",text:$passWord)
                    .multilineTextAlignment(.center)
                    .focused($focus, equals: .password)
            }.padding(.all)
            
            HStack{
                Text("验证码")
                Spacer()
                TextField("请输入验证码",text:$code)
                    .multilineTextAlignment(.center)
                    .focused($focus, equals: .code)
            }.padding(.all)
            
            Spacer()
            // 提示语和button在一起
            Text(res).foregroundColor(color)
            
            Button("登陆"){
                showAlert.toggle();
                color=.red
                // button 的点击事件action,做一个简单的判断
                // 修改 res 的名称,以及res的颜色
                if(userName==""){
                    res="请输入用户名!";
                    return ;
                }
                if(passWord==""){
                    res="请输入密码!"
                    return ;
                }
                if(code==""){
                    res="请输入验证码";
                    return ;
                }
                color=.green;
                res="登陆成功"
                // 清空表单数据
                userName="";
                passWord="";
                code="";
            }.buttonStyle(.bordered)
            .alert(isPresented: $showAlert){
                Alert(
                    title: Text("提示"),
                    message: Text(res),
                    primaryButton: .default(Text("取消")),
                    secondaryButton: .destructive(Text("确定")){
                        if(res=="请输入用户名!"){
                            // 没有用户名
                            focus=.name
                        }
                        if(res=="请输入密码!"){
                            focus=.password
                        }
                        if(res=="请输入验证码!"){
                            focus=.code
                        }
                        if(res=="登陆成功" || res=="请输入。。。"){
                            focus=.clear
                        }
                    }
                )
            }
        }
        .padding()
    }
}
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

运行得到以下的结果

在这里插入图片描述

总结

  1. TextField 的 .focused($focus, .name) 使用
  2. enum 的基本使用
  3. Alert 的基本使用

门的HTML - tabindex 的作用

HTML 的 tabindex 属性开发过程中一般不会使用到,最近开发中有个需求兼顾富交互,便总结了一下。本篇文章同时收录在我的【前端知识点】中,Github链接请点击阅读原文直达,欢迎 Star

兼容性:Safari不支持!

阅读本文您将收获

  • tabindex的作用
  • tabindex的使用
  • 如何利用 tabindex 创造更好的用户体验

前言

在我们日常使用网页的过程中,可以通过键盘控制一些元素的聚焦,从而达到便捷访问的目的

element 分为 focusable 和 非focusable ,如果使用了tabindex就可以改变相关的行为

在HTML中有6个元素默认支持聚焦:

  • 带 href 属性的 <a> 标签
  • 带 href 属性的 <link> 标签
  • <button></button> 标签
  • <input /> 标签 (排除带有 type="hidden" 属性的)
  • <select></select> 标签
  • <textarea></textarea> 标签

以上的元素默认都可以使用 Tab 键,以及 JS focus() 方法聚焦

document.querySelector("a").focus();

使用 tab键 进行聚焦元素时,聚焦的顺序等于元素在代码中的出现先后顺序,当我们进行富交互优化时,就需要用到 tabindex 这个属性来帮助我们进行更好用户体验的优化了

tabindex的作用

①元素是否能聚焦:通过键盘这类输入设备,或者通过 JS focus() 方法

②元素什么时候能聚焦:在用户通过键盘与页面交互时

通俗来说:就是当用户使用键盘时,tabindex用来定位html元素,即使用tab键时焦点的顺序。

tabindex的范围

tabindex理论上可以使用在几乎所有元素上

  • tabindex 理论上可以用在几乎所有元素上,不管这个元素默认是否支持聚焦

tabindex 有三个值:0,-N(通常是-1),N(正值)

  • tabindex=0,该元素可以用tab键获取焦点
    • 且访问的顺序是按照元素在文档中的顺序来focus,即使采用了浮动改变了页面中显示的顺序,依然是按照html文档中的顺序来定位
  • tabindex<=-1,该元素用tab键获取不到焦点,但是可以通过js获取
    • 这样就便于我们通过js设置上下左右键的响应事件来focus
    • 取值 -1~-999 之间没有区别,但为了可读性和一致性考虑,推荐使用 -1
  • tabindex>=1,该元素可以用tab键获取焦点,而且优先级大于tabindex=0
    • 不过在tabindex>=1时,数字越小,越先定位到;
    • 如果多个元素拥有相同的 tabindex ,他们的相对顺序按照他们在当前DOM中的先后顺序决定

tabindex的使用

tabindex 决定聚焦顺序

  • 可聚焦元素中,正整数数值越大,顺序越往后,正整数数值的节点顺序比0值的节点靠前
  • 代码:
// HTML
<button type="button" tabindex="1">tabindex === 1</button>
<button type="button" tabindex="999">tabindex === 999</button>
<button type="button" tabindex="0">tabindex === 0</button>
  • 效果:
  • 可聚焦元素中,相同 tabindex 数值的节点,根据 DOM节点 先后顺序决定聚焦顺序
  • 代码:
// HTML
<button type="button" tabindex="0">tabindex === 0</button>
<button type="button" tabindex="1">tabindex === 1</button>
<button type="button" tabindex="999">tabindex === 999</button>
<button type="button" tabindex="0">tabindex === 0</button>
  • 效果:

tabindex 决定是否聚焦

  • 节点的 tabindex 设置为 -1 时,当前节点使用 tab键 不能聚焦
  • 代码:
// HTML
<button type="button">未设置tabindex</button>
<button type="button" tabindex="-1">tabindex === -1</button>
<button type="button" tabindex="0">tabindex === 0</button>
<button type="button" tabindex="1">tabindex === 1</button>
  • 效果:

tabindex 与JS编程聚焦

  • 通过 tabindex 结合JS可以让默认不支持聚焦的节点进行聚焦,tabindex 为不超出范围的任何整数值都可以
  • 代码:
// HTML
<button type="button" @click="clickBtn()">点击让DIV聚焦</button>
<div id="FocusDiv" ref="FocusDiv" tabindex="-1">这是一个div</div>

// JS
clickBtn: function() {
    document.getElementById('FocusDiv').focus();
}
  • 效果:

如何利用 tabindex 创造更好的用户体验

针对自定义标签进行富交互优化

  • 我们在创建一个自定义的标签时,如果默认行为中不包含聚焦事件,我们可以使用 tabindex 为它增加聚焦功能,从而可以像很多可聚焦节点一样进行顺次焦点聚焦了

针对特定节点禁止聚焦操作

  • 某些浮层及上层节点,如 toast组件、模态框、侧边弹出信息等,我们不希望节点被用户聚焦捕获,可以将节点的 tabindex 设置为 -1,就能避免这一问题

复杂列表控制聚焦顺序

  • 一些复杂的树形结构或者列式结构,如果需要用户操作顺序按照我们预想的书序进行聚焦,可以利用tabindex 值的大小来进行处理。