Compare commits

...

3 Commits

Author SHA1 Message Date
阿斌
3815a6e237
Pre Merge pull request !46 from 阿斌/N/A 2026-06-08 07:06:49 +00:00
lin
0bd42d00b5 修复国标级联移除移除大量共享通道失败的BUG,修复国标级联推流鉴权失败的BUG 2026-06-08 15:06:25 +08:00
阿斌
c011389c3f
SDP 注入攻击 / 非法 SDP 协议数据
java.text.ParseException: [C@2f1fec26
ID expected
        at gov.nist.core.LexerCore.match(LexerCore.java:229)
        at gov.nist.javax.sdp.parser.OriginFieldParser.originField(OriginFieldParser.java:90)
        at gov.nist.javax.sdp.parser.OriginFieldParser.parse(OriginFieldParser.java:108)
        at gov.nist.javax.sdp.parser.SDPAnnounceParser.parse(SDPAnnounceParser.java:113)
        at javax.sdp.SdpFactory.createSessionDescription(SdpFactory.java:129)
        at com.genersoft.iot.vmp.gb28181.utils.SipUtils.parseSDP(SipUtils.java:229)
        at com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.InviteRequestProcessor.decode(InviteRequestProcessor.java:275)
        at com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.InviteRequestProcessor.process(InviteRequestProcessor.java:125)
        at com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver.processRequest(SIPProcessorObserver.java:71)
        at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
        at java.base/java.lang.reflect.Method.invoke(Method.java:580)
        at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:359)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
        at org.springframework.aop.interceptor.AsyncExecutionInterceptor.lambda$invoke$0(AsyncExecutionInterceptor.java:114)
        at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
        at java.base/java.lang.Thread.run(Thread.java:1583)
java.text.ParseException: o=- ' OR 'a'='a'; -- 1 IN IP4 179.43.150.26
        at gov.nist.javax.sdp.parser.OriginFieldParser.originField(OriginFieldParser.java:103)
        at gov.nist.javax.sdp.parser.OriginFieldParser.parse(OriginFieldParser.java:108)
        at gov.nist.javax.sdp.parser.SDPAnnounceParser.parse(SDPAnnounceParser.java:113)
        at javax.sdp.SdpFactory.createSessionDescription(SdpFactory.java:129)
        at com.genersoft.iot.vmp.gb28181.utils.SipUtils.parseSDP(SipUtils.java:229)
        at com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.InviteRequestProcessor.decode(InviteRequestProcessor.java:275)
        at com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.InviteRequestProcessor.process(InviteRequestProcessor.java:125)
        at com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver.processRequest(SIPProcessorObserver.java:71)
        at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
        at java.base/java.lang.reflect.Method.invoke(Method.java:580)
        at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:359)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
        at org.springframework.aop.interceptor.AsyncExecutionInterceptor.lambda$invoke$0(AsyncExecutionInterceptor.java:114)
        at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
        at java.base/java.lang.Thread.run(Thread.java:1583)


Signed-off-by: 阿斌 <38912748@qq.com>
2026-03-21 16:15:47 +00:00
4 changed files with 62 additions and 57 deletions

View File

@ -36,6 +36,8 @@ import java.util.stream.Collectors;
@RequiredArgsConstructor
public class PlatformChannelServiceImpl implements IPlatformChannelService {
private static final int BATCH_SIZE = 500;
private final PlatformChannelMapper platformChannelMapper;
private final EventPublisher eventPublisher;
@ -450,34 +452,7 @@ public class PlatformChannelServiceImpl implements IPlatformChannelService {
}
List<CommonGBChannel> channelListShare = platformChannelMapper.queryShare(platformId, null);
Assert.notEmpty(channelListShare, "未共享任何通道");
int result = platformChannelMapper.removeChannelsWithPlatform(platformId, channelListShare);
if (result > 0) {
// 查询通道相关的分组信息
Set<Region> regionSet = regionMapper.queryByChannelList(channelListShare);
Set<Region> deleteRegion = deleteEmptyRegion(regionSet, platformId);
if (!deleteRegion.isEmpty()) {
for (Region region : deleteRegion) {
channelListShare.add(0, CommonGBChannel.build(region));
}
}
// 查询通道相关的分组信息
Set<Group> groupSet = groupMapper.queryByChannelList(channelListShare);
Set<Group> deleteGroup = deleteEmptyGroup(groupSet, platformId);
if (!deleteGroup.isEmpty()) {
for (Group group : deleteGroup) {
channelListShare.add(0, CommonGBChannel.build(group));
}
}
// 发送消息
try {
// 发送catalog
eventPublisher.catalogEventPublish(platform, channelListShare, CatalogEvent.DEL);
} catch (Exception e) {
log.warn("[移除全部关联通道] 发送失败,数量:{}", channelListShare.size(), e);
}
}
return result;
return removeChannelsFromDb(platform, platformId, channelListShare);
}
@Override
@ -494,6 +469,44 @@ public class PlatformChannelServiceImpl implements IPlatformChannelService {
removeChannels(platformId, channelList);
}
private <T> List<List<T>> partition(List<T> list, int size) {
List<List<T>> result = new ArrayList<>();
for (int i = 0; i < list.size(); i += size) {
result.add(list.subList(i, Math.min(i + size, list.size())));
}
return result;
}
private int removeChannelsFromDb(Platform platform, Integer platformId, List<CommonGBChannel> channelList) {
List<List<CommonGBChannel>> batches = partition(channelList, BATCH_SIZE);
int totalResult = 0;
for (List<CommonGBChannel> batch : batches) {
totalResult += platformChannelMapper.removeChannelsWithPlatform(platformId, batch);
}
if (totalResult > 0) {
Set<Region> regionSet = regionMapper.queryByChannelList(channelList);
Set<Region> deleteRegion = deleteEmptyRegion(regionSet, platformId);
if (!deleteRegion.isEmpty()) {
for (Region region : deleteRegion) {
channelList.add(0, CommonGBChannel.build(region));
}
}
Set<Group> groupSet = groupMapper.queryByChannelList(channelList);
Set<Group> deleteGroup = deleteEmptyGroup(groupSet, platformId);
if (!deleteGroup.isEmpty()) {
for (Group group : deleteGroup) {
channelList.add(0, CommonGBChannel.build(group));
}
}
try {
eventPublisher.catalogEventPublish(platform, channelList, CatalogEvent.DEL);
} catch (Exception e) {
log.warn("[取消共享通道] 发送失败,数量:{}", channelList.size(), e);
}
}
return totalResult;
}
@Transactional
public int removeChannelList(Integer platformId, List<CommonGBChannel> channelList) {
Platform platform = platformMapper.query(platformId);
@ -513,36 +526,12 @@ public class PlatformChannelServiceImpl implements IPlatformChannelService {
}
return result;
}
String deviceIds = channelList.stream().map(CommonGBChannel::getGbDeviceId).collect(Collectors.joining(","));
int result = platformChannelMapper.removeChannelsWithPlatform(platformId, channelList);
int result = removeChannelsFromDb(platform, platformId, channelList);
if (result <= 0) {
String deviceIds = channelList.stream().map(CommonGBChannel::getGbDeviceId).collect(Collectors.joining(","));
log.info("[取消共享通道] 平台{}未关联通道: {}", platformId, deviceIds);
return 0;
}
// 查询通道相关的分组信息
Set<Region> regionSet = regionMapper.queryByChannelList(channelList);
Set<Region> deleteRegion = deleteEmptyRegion(regionSet, platformId);
if (!deleteRegion.isEmpty()) {
for (Region region : deleteRegion) {
channelList.add(0, CommonGBChannel.build(region));
}
}
// 查询通道相关的分组信息
Set<Group> groupSet = groupMapper.queryByChannelList(channelList);
Set<Group> deleteGroup = deleteEmptyGroup(groupSet, platformId);
if (!deleteGroup.isEmpty()) {
for (Group group : deleteGroup) {
channelList.add(0, CommonGBChannel.build(group));
}
}
// 发送消息
try {
// 发送catalog
eventPublisher.catalogEventPublish(platform, channelList, CatalogEvent.DEL);
} catch (Exception e) {
log.warn("[取消共享通道] 发送失败,数量:{}", channelList.size(), e);
}
return result;
}

View File

@ -861,7 +861,9 @@ public class PlayServiceImpl implements IPlayService {
log.info("[Invite 200OK] 收到invite 200, 发现下级自定义了ssrc: {}", ssrcInResponse);
String oldStreamId = String.format("%08x", Long.parseLong(ssrcInfo.getSsrc())).toUpperCase();
String newStreamId = String.format("%08x", Long.parseLong(ssrcInResponse)).toUpperCase();
receiveRtpServerService.refreshAuthenticateInfo(oldStreamId, newStreamId);
if (!mediaServerItem.isRtpEnable()) { // 多端口时按照端口绑定了stream即使stream与ssrc不一致也不会影响
receiveRtpServerService.refreshAuthenticateInfo(oldStreamId, newStreamId);
}
// ssrc 不一致
if (mediaServerItem.isRtpEnable()) {
// 多端口

View File

@ -177,6 +177,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
String sendSsrc = sendSsrcFactory.getSendSsrc(
"Play".equalsIgnoreCase(finalInviteInfo.getSessionName()) ? "0" : "1");
finalInviteInfo.setSsrc(sendSsrc);
log.info("[上级INVITE] 使用自定义SSRC: {}", sendSsrc);
}
// 构建sendRTP内容
SendRtpInfo sendRtpItem = sendRtpServerService.createSendRtpInfo(streamInfo.getMediaServer(),
@ -224,8 +225,6 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
} catch (SipException | InvalidArgumentException | ParseException e) {
log.error("[命令发送失败] 上级INVITE 发送 200SDP: {}", e.getMessage());
}
}
}));
}

View File

@ -205,6 +205,21 @@ public class SipUtils {
}
public static Gb28181Sdp parseSDP(String sdpStr) throws SdpParseException {
// 校验拦截空内容与注入攻击特征
if (sdpStr == null || sdpStr.trim().isEmpty()) {
throw new SdpParseException(0, 0, "SDP内容为空");
}
// 标准SDP每行格式固定为 "x=value"不存在SQL关键字出现则视为注入攻击
String sdpUpper = sdpStr.toUpperCase();
if (sdpUpper.contains("' OR '") || sdpUpper.contains("' OR 1") || sdpUpper.contains(" OR 1=1")
|| sdpUpper.contains("--") || sdpUpper.contains("/*") || sdpUpper.contains("*/")
|| sdpUpper.contains("DROP ") || sdpUpper.contains("INSERT ") || sdpUpper.contains("UPDATE ")
|| sdpUpper.contains("DELETE ") || sdpUpper.contains("UNION ") || sdpUpper.contains("SELECT ")) {
log.error("[SDP注入攻击] 检测到非法SDP内容已拒绝解析内容长度: {}", sdpStr.length());
throw new SdpParseException(0, 0, "非法SDP内容");
}
//校验结束
// jainSip不支持y= f=字段 移除以解析
int ssrcIndex = sdpStr.indexOf("y=");